user1488803
user1488803

Reputation: 173

XSLT Add Parent Element to Children

I am trying to add one element from some XML to certain children elements in the same XML. The element in question is repeated already so the value has to be from the correct section of the XML. Here is the source XML:

<Extract>
  <Packet>
    <TXREQUESTID>694154</TXREQUESTID>
    <Data>
      <Property>
        <Key>phoneNumber</Key>
      </Property>
      <Property>
        <Key>ownerName</Key>
      </Property>
    </Data>
    <Milestones>
      <Milestone>
        <Code>123123</Code>
      </Milestone>
      <Milestone>
        <Code>123125</Code>
      </Milestone>
    </Milestones>
  </Packet>
  <Packet>
    <TXREQUESTID>694155</TXREQUESTID>
    <Data>
      <Property>
        <Key>phoneNumber</Key>
      </Property>
      <Property>
        <Key>ownerName</Key>
      </Property>
    </Data>
    <Milestones>
      <Milestone>
        <Code>789789</Code>
      </Milestone>
      <Milestone>
        <Code>123126</Code>
      </Milestone>
    </Milestones>
  </Packet>
</Extract>

I need to replicate the TXREQUESTID element as an element in the child Property and Milestone elements. When finished it needs to look like this:

<Extract>
  <Packet>
    <TXREQUESTID>694154</TXREQUESTID>
    <Data>
      <Property>
        <Key>phoneNumber</Key>
        <TXREQUESTID>694154</TXREQUESTID>
      </Property>
      <Property>
        <Key>ownerName</Key>
        <TXREQUESTID>694154</TXREQUESTID>
      </Property>
    </Data>
    <Milestones>
      <Milestone>
        <Code>123123</Code>
        <TXREQUESTID>694154</TXREQUESTID>
      </Milestone>
      <Milestone>
        <Code>123125</Code>
        <TXREQUESTID>694154</TXREQUESTID>
      </Milestone>
    </Milestones>
  </Packet>
  <Packet>
    <TXREQUESTID>694155</TXREQUESTID>
    <Data>
      <Property>
        <Key>phoneNumber</Key>
        <TXREQUESTID>694155</TXREQUESTID>
      </Property>
      <Property>
        <Key>ownerName</Key>
        <TXREQUESTID>694155</TXREQUESTID>
      </Property>
    </Data>
    <Milestones>
      <Milestone>
        <Code>789789</Code>
        <TXREQUESTID>694155</TXREQUESTID>
      </Milestone>
      <Milestone>
        <Code>123126</Code>
        <TXREQUESTID>694155</TXREQUESTID>
      </Milestone>
    </Milestones>
  </Packet>
</Extract>

I've spent hours on this and haven't had any luck. This seems like it should be simple but I'm finding the XSLT syntax baffling. Can anyone point me in the right direction?

Upvotes: 0

Views: 767

Answers (1)

Daniel Haley
Daniel Haley

Reputation: 52888

Start with the identity transform and override it for the elements you want to change (Property and Milestone)

XML Input

<Extract>
    <Packet>
        <TXREQUESTID>694154</TXREQUESTID>
        <Data>
            <Property>
                <Key>phoneNumber</Key>
            </Property>
            <Property>
                <Key>ownerName</Key>
            </Property>
        </Data>
        <Milestones>
            <Milestone>
                <Code>123123</Code>
            </Milestone>
            <Milestone>
                <Code>123125</Code>
            </Milestone>
        </Milestones>
    </Packet>
    <Packet>
        <TXREQUESTID>694155</TXREQUESTID>
        <Data>
            <Property>
                <Key>phoneNumber</Key>
            </Property>
            <Property>
                <Key>ownerName</Key>
            </Property>
        </Data>
        <Milestones>
            <Milestone>
                <Code>789789</Code>
            </Milestone>
            <Milestone>
                <Code>123126</Code>
            </Milestone>
        </Milestones>
    </Packet>
</Extract>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <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="Milestone|Property">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()|ancestor::Packet/TXREQUESTID"/>
        </xsl:copy>        
    </xsl:template>

</xsl:stylesheet>

XML Output

<Extract>
   <Packet>
      <TXREQUESTID>694154</TXREQUESTID>
      <Data>
         <Property>
            <TXREQUESTID>694154</TXREQUESTID>
            <Key>phoneNumber</Key>
         </Property>
         <Property>
            <TXREQUESTID>694154</TXREQUESTID>
            <Key>ownerName</Key>
         </Property>
      </Data>
      <Milestones>
         <Milestone>
            <TXREQUESTID>694154</TXREQUESTID>
            <Code>123123</Code>
         </Milestone>
         <Milestone>
            <TXREQUESTID>694154</TXREQUESTID>
            <Code>123125</Code>
         </Milestone>
      </Milestones>
   </Packet>
   <Packet>
      <TXREQUESTID>694155</TXREQUESTID>
      <Data>
         <Property>
            <TXREQUESTID>694155</TXREQUESTID>
            <Key>phoneNumber</Key>
         </Property>
         <Property>
            <TXREQUESTID>694155</TXREQUESTID>
            <Key>ownerName</Key>
         </Property>
      </Data>
      <Milestones>
         <Milestone>
            <TXREQUESTID>694155</TXREQUESTID>
            <Code>789789</Code>
         </Milestone>
         <Milestone>
            <TXREQUESTID>694155</TXREQUESTID>
            <Code>123126</Code>
         </Milestone>
      </Milestones>
   </Packet>
</Extract>

If element order matters, split the xsl:apply-templates like this:

<xsl:apply-templates select="@*|node()"/>
<xsl:apply-templates select="ancestor::Packet/TXREQUESTID"/>            

Upvotes: 2

Related Questions