Andy Zhu
Andy Zhu

Reputation: 23

Add parent element and rename the child element

I am trying to loop child elements under import and export. Create a parent element fields and put all the elements which the name is field into it, just under import, not include the elements field under structure, Create element structures over all elements structure, and the last work is rename all the element with the value of attribute name. I just know copy all of them first and can not go to next step to create the right template.

input:

<?xml version='1.0'?>
<jco name="TEST" timestamp="1275691115508" version="1.0">
<import>
    <field name="RESERVED_IN">12345</field>
    <structure name="GM_HEADER">
                <field name="PSTNG_DATE">2004-07-02</field>
        <field name="DOC_DATE">2004-04-02</field>
    </structure>
    <structure name="TESTRUN">
        <field name="TESTRUN"></field>
    </structure>
</import>
<export>
    <field name="RESERVED_OUT"></field>
    <structure name="GM_HEADER_RET">
        <field name="MAT_DOC"></field>
        <field name="DOC_YEAR">0000</field>
    </structure>
</export>
</jco>

desired output:

<?xml version="1.0" ?>
<jco version="1.0" name="TEST">
    <import>
        <fields>
            <RESERVED_IN>12345</RESERVED_IN>
        </fields>
        <structures>
            <GM_HEADER>
                <PSTNG_DATE>2004-07-02</PSTNG_DATE>
                <DOC_DATE>2004-04-02</DOC_DATE>
            </GM_HEADER>
            <TESTRUN>
                <TESTRUN></TESTRUN>
            </TESTRUN>
        </structures>
   </import>
   <export>
       <fields>
           <RESERVED_OUT></RESERVED_OUT>
       </fields>
       <structures>
           <GM_HEADER_RET>
               <MAT_DOC></MAT_DOC>
               <DOC_YEAR>0000</DOC_YEAR>
           </GM_HEADER_RET>
       </structures>
   </export>
</jco>

Below is my xslt, but it seems messed up.

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

        <xsl:template match="import">
            <fields>
                <xsl:for-each select="/field">
                    <xsl:call-template name="field" />
                </xsl:for-each>
            </fields>
            <structures>
                <xsl:for-each select="/structure">
                    <xsl:element name="{@name}">
                        <xsl:value-of select="." />
                    </xsl:element>
                    <xsl:call-template name="field" />
                </xsl:for-each>
            </structures>
        </xsl:template>

        <xsl:template name="field">
            <xsl:for-each select="/field">
                    <xsl:element name="{@name}">
                        <xsl:value-of select="." />
                    </xsl:element>
                </xsl:for-each>
        </xsl:template>

Upvotes: 2

Views: 1382

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167696

Use templates and apply-templates, not for-each, and it works out rather elegantly:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs">

<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="import | export">
  <xsl:copy>
    <fields>
      <xsl:apply-templates select="field"/>
    </fields>
    <structures>
      <xsl:apply-templates select="structure"/>
    </structures>
  </xsl:copy>
</xsl:template>

<xsl:template match="field | structure">
  <xsl:element name="{@name}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

Upvotes: 2

Related Questions