简体   繁体   中英

XSLT: Copy an attribute from one node to another

I am relatively new to XSLT and i am working on a project involving xml and xslt1.0.

I have a xml code (simplified version) that looks like

<visualChildren>
    <object class="com.zerog.ia.installer.InstallSet" >
        <installChildren>
            <object class="com.zerog.ia.installer.InstallBundle" objectID="33110emc908m">
                <property></property>
            </object>
            <object class="com.zerog.ia.installer.InstallBundle" objectID="43110emc9667m">
                <property></property>
            </object>
        </installChildren>
    </object>
</visualChildren>

I would need to collect all the object ids iteratively and store as

<object RefId={ObjectId} /> 

under visualChildren. Expected result is

<visualChildren>
    <object class="com.zerog.ia.installer.InstallSet" >
        <installChildren>
            <object class="com.zerog.ia.installer.InstallBundle" objectID="33110emc908m">
                <property></property>
            </object>
            <object class="com.zerog.ia.installer.InstallBundle" objectID="43110emc9667m">
                <property></property>
            </object>
        </installChildren>
    </object>
 <object RefId=33110emc908m /> 
 <object RefId=43110emc9667m /> 
</visualChildren>

Could anyone help me to achieve this with xslt 1.0

You can modify the identity transformation to copy over everything exactly except for the visualChildren/object elements, which can be copied over as-is plus the RefId attribute you request:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes"/>

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

  <xsl:template match="visualChildren/object">
    <xsl:copy>
      <xsl:attribute name="RefId">
        <xsl:for-each select="//@objectID">
          <xsl:value-of select="."/>
          <xsl:if test="position() != last()">
            <xsl:text> </xsl:text>
          </xsl:if>
        </xsl:for-each>
      </xsl:attribute>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Applying the above XSLT to your input XML:

<visualChildren>
    <object class="com.zerog.ia.installer.InstallSet" >
        <installChildren>
            <object class="com.zerog.ia.installer.InstallBundle" objectID="33110emc908m">
                <property></property>
            </object>
            <object class="com.zerog.ia.installer.InstallBundle" objectID="43110emc9667m">
                <property></property>
            </object>
        </installChildren>
    </object>
</visualChildren>

Yields the following output XML:

<?xml version="1.0" encoding="UTF-8"?>
<visualChildren>
    <object RefId="33110emc908m 43110emc9667m"
           class="com.zerog.ia.installer.InstallSet">
        <installChildren>
            <object class="com.zerog.ia.installer.InstallBundle" objectID="33110emc908m">
                <property/>
            </object>
            <object class="com.zerog.ia.installer.InstallBundle" objectID="43110emc9667m">
                <property/>
            </object>
        </installChildren>
    </object>
</visualChildren>

As requested.

Note: Should you want all of the @objectID attributes below a given visualChildren/object element rather than all of the @objectID attributes in the entire document, then change

    <xsl:for-each select="//@objectID">

to

    <xsl:for-each select=".//@objectID">

Try it this way:

XSLT 1.0

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

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

<xsl:template match="/visualChildren">
     <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:for-each select=".//@objectID">
            <object RefId="{.}"/> 
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Note:

If the objects you want to collect are always under installChildren , then replace:

<xsl:for-each select=".//@objectID">

with the more efficient:

<xsl:for-each select="object/installChildren/object/@objectID">

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM