首页 > 解决方案 > XSLT for-each 替换元素名称中的文本

问题描述

我是 XSLT 的新手。我有一个已转换为 XML 的 EDI 文件

<?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>

我正在尝试像这样为每个 PO1 节点创建一个 ACK​​ 节点(如果有多个 PO 节点(即 PO1、PO2、PO3 等)为每个节点创建一个 ACK​​ 也会很棒)

      <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>

我可以使用 PO1 子节点的值添加 ACK 节点,但无法为每个子节点创建一个节点。我只是不确定此时该去哪里创建节点并将子节点的名称从 PO102 更改为 ACK2、PO105 更改为 ACK5 等。

这是我正在使用的 XSLT:

<?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>

提前致谢

标签: xmlxsltlocal-name

解决方案


这就是你需要的。

<?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>

对于 xslt 1.0。

利用

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

推荐阅读