3

I need to transform this structure

<A>
<B>value1</B>
</A>
<A>
<B>value2</B>
</A>

into

<A>
<B>value1<B>
<B>value2<B>
</A>

What is best solution using XSLT-1.0? Thank you!

PS: I tried this code:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>   
<xsl:key name="group_a" match="//A" use="B"/> 
<xsl:template match="/Test"> <a-node> <xsl:for-each select="//A"> <b-node> 
<xsl:value-of select="//A/B"/> </b-node> </xsl:for-each> </a-node> 
</xsl:template> 
</xsl:stylesheet> 

but it returns only first value:

<?xml version="1.0" encoding="utf-8"?> <a-node mlns:fo="http://www.w3.org/1999/XSL/Format"> <b-node>value1</b-node> <b-node>value1</b-node> </a-node> 

but I need:

<?xml version="1.0" encoding="utf-8"?> <a-node xmlns:fo="http://www.w3.org/1999/XSL/Format"> <b-node>value1</b-node> <b-node>value2</b-node> </a-node>
0

3 Answers 3

2

This style-sheet ...

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
    <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
    <xsl:template match="/">
       <A>
        <xsl:apply-templates select="*/A/B"/>
       </A>
    </xsl:template>

    <xsl:template match="B">
      <B><xsl:value-of select="."/></B>
    </xsl:template>
</xsl:stylesheet>

... will transform ...

<root>
<A>
<B>value1</B>
</A>
<A>
<B>value2</B>
</A>
</root>

... into this ...

 <A><B>value1</B><B>value2</B></A>
Sign up to request clarification or add additional context in comments.

Comments

1

Since it seems you need to collapse all the children under a single node, then you don't need the foreach on "A", you can move directly to the "B" children

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
    <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
    <xsl:template match="/">
        <A>
            <xsl:for-each select="//A/B">
                <B>
                    <xsl:value-of select="./text()"/>
                </B>
            </xsl:for-each>
        </A>
    </xsl:template>
</xsl:stylesheet>

EDIT As per @Sean's comment, note that // should never be used in real life. Replace // with the path from your real root Element.

2 Comments

Functionally correct but inefficient. Better to use a template style and avoid unnecessary use of the // operator.
@Sean - sure - Agreed never use // but had no choice since OP's xml sample has no root element :)
0

This transformation uses one of the most fundamental XSLT design patterns -- overriding the identity transform. Thus, it is easier to write, understand, maintain and extend:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="A[1]">
  <A>
    <xsl:apply-templates select="node()|following-sibling::A/node()"/>
  </A>
 </xsl:template>
 <xsl:template match="A"/>
</xsl:stylesheet>

When this transformation is applied on the following XML document (obtained by wrapping the provided XML fragment into a single top element -- to make this a well-formed XML document):

<t>
    <A>
        <B>value1</B>
    </A>
    <A>
        <B>value2</B>
    </A>
</t>

the wanted, correct result is produced:

<t>
   <A>
      <B>value1</B>
      <B>value2</B>
   </A>
</t>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.