使用 XSLT 将 XML 元素移动到不同的节点

Move XML element to different node using XSLT

Below is the XML Input payload. I'm looking for an xml output should have "type" element inside the each Address node. Below is the incoming request XML

<rsp:response xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rsp="rsp.com/employee/Response/v30"
xmlns:res="res.com/Member/details/v1"
xmlns:resp="resp.com/details/v1">
        <res:employee>
            <resp:Employee>
                <resp:FirstName>abc</resp:FirstName>
                <resp:middleName></resp:middleName>
                <resp:details>
                    <resp:Details>
                        <resp:type>postal</resp:type>  
                        <resp:Addresses>
                            <resp:Address>
                                <resp:country>XYZ</resp:country>
                            </resp:Address>
                        </resp:Addresses>
                    </resp:Details>
                    <resp:Details>
                        <resp:type>ofc</resp:type> 
                        <resp:Addresses>
                            <resp:Address>
                                <resp:country>XYZ</resp:country>
                            </resp:Address>
                        </resp:Addresses>
                    </resp:Details>
                </resp:details>
            </resp:Employee>
        </res:employee>

Here is the XSLT used and it is not giving desired output. Using this XSLT all "type" elements is reflecting in each address block.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"    
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rsp="rsp.com/employee/Response/v30"
xmlns:res="res.com/Member/details/v1"
xmlns:resp="resp.com/details/v1"
version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>  
<xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
</xsl:template>  
<xsl:template match="//*[local-name()='response']/*[local-name()='employee']/*[local-name()='Employee']/*[local-name()='details']/*[local-name()='Details']/*[local-name()='Addresses']/*[local-name()='Address']">
    <xsl:copy>
        <xsl:apply-templates/>            
        <xsl:for-each select="//*[local-name()='response']/*[local-name()='employee']/*[local-name()='Employee']/*[local-name()='details']/*[local-name()='Details']/*[local-name()='type']">
            <xsl:copy-of select="."/>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>
<xsl:template match="//*[local-name()='response']/*[local-name()='employee']/*[local-name()='Employee']/*[local-name()='details']/*[local-name()='Details']/*[local-name()='type']"/>

Desired Output XML

<rsp:response
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rsp="rsp.com/employee/Response/v30"
xmlns:res="res.com/Member/details/v1"
xmlns:resp="resp.com/details/v1">
<res:employee>
    <resp:Employee>
        <resp:FirstName>abc</resp:FirstName>
        <resp:middleName/>
        <resp:details>
            <resp:Details>
                <resp:Addresses>
                    <resp:Address>
                        <resp:country>XYZ</resp:country>
                        <resp:type>postal</resp:type>
                    </resp:Address>
                </resp:Addresses>
            </resp:Details>
            <resp:Details>
                <resp:Addresses>
                    <resp:Address>
                        <resp:country>XYZ</resp:country>
                        <resp:type>ofc</resp:type>
                    </resp:Address>
                </resp:Addresses>
            </resp:Details>
        </resp:details>
    </resp:Employee>
</res:employee>

这样试试:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:resp="resp.com/details/v1">
<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="resp:Address">
    <xsl:copy>
        <xsl:apply-templates/>
        <xsl:copy-of select="../../resp:type"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="resp:type"/>

</xsl:stylesheet>

重新尝试:

  1. 永远不需要使用像 *[local-name()='type'];

    这样的 hack
  2. 你应该弄清楚//是什么意思。