XSLT for-each replacing text in element name

501 views Asked by At

I'm new to XSLT. I have an EDI file that I've converted to XML

<?xml version="1.0" encoding="UTF-8"?>
<ns0:X12_00401_850 xmlns:ns0="....">
    .
    .
    .
   <ns0:PO1Loop1>
      <ns0:PO1>
         <PO101>000001</PO101>
         <PO102>1</PO102>
         <PO103>EA</PO103>
         <PO104>3531.65</PO104>
         <PO105>QT</PO105>
         <PO106>VP</PO106>
         <PO107>ACS5048-001</PO107>
         <PO108>BP</PO108>
         <PO109>Q90001</PO109>
      </ns0:PO1>
   </ns0:PO1Loop1>
   .
   .
   .
</ns0:X12_00401_850>

I'm trying to create an ACK node for each PO1 node like this (it would also be great that if there were multiple PO nodes (i.e. PO1, PO2, PO3, etc.) to create an ACK for each)

      <ns0:PO1>
         <PO101>000001</PO101>
         <PO102>1</PO102>
         <PO103>EA</PO103>
         <PO104>3531.65</PO104>
         <PO105>QT</PO105>
         <PO106>VP</PO106>
         <PO107>ACS5048-001</PO107>
         <PO108>BP</PO108>
         <PO109>Q90001</PO109>
      </ns0:PO1>
      <ns0:ACK1>
         <ACK101>000001</ACK101>
         <ACK102>1</ACK102>
         <ACK103>EA</ACK103>
         <ACK104>3531.65</ACK104>
         <ACK105>QT</ACK105>
         <ACK106>VP</ACK106>
         <ACK107>ACS5048-001</ACK107>
         <ACK108>BP</ACK108>
         <ACK109>Q90001</ACK109>
      </ns0:ACK1>

I can add the ACK node with the values of the PO1 child nodes, but I can't get a node created for each. I'm just not sure where to go at this point to create the node and change the name of the children nodes from PO102 to ACK2, PO105 to ACK5, etc.

Here is my XSLT that I'm working with:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns0="http://Citrix.EDI.Partners.IngramMicroUS.Schemas.850"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

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

    <xsl:template match="ST01">
        <ST01>855</ST01>
    </xsl:template>

    <xsl:template match="ns0:PO1">
        <xsl:copy-of select="."/>
        <ns0:ACK1>
            <xsl:for-each select="./*">

            </xsl:for-each
        </ns0:ACK1>
    </xsl:template>    
</xsl:stylesheet>

Thanks in advance

1

There are 1 answers

4
Ed Bangga On BEST ANSWER

Here's what you need.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns0="http://Citrix.EDI.Partners.IngramMicroUS.Schemas.850"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

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

    <xsl:template match="ST01">
        <ST01>855</ST01>
    </xsl:template>

    <xsl:template match="ns0:PO1">
        <xsl:copy-of select="."/>
        <ns0:ACK1>
            <xsl:for-each select="./*">
                <xsl:variable name="ack_el" select="replace(local-name(), 'PO', 'ACK')"/>
                <xsl:element name="{$ack_el}">
                    <xsl:copy-of select="text()"/>
                </xsl:element>
            </xsl:for-each>
        </ns0:ACK1>
    </xsl:template>    
</xsl:stylesheet>

For xslt 1.0.

use

        <xsl:variable name="ack_el" select="concat('ACK', substring(local-name(), 3, string-length(local-name())))"/>