通过 xslt 重新排列 xml 节点(包括子节点)

2023-11-26

我有一个 xml 文档,现在我想将其转换为另一个内容相同但元素顺序不同的 xml 文档。

原始的xml文档如下:

<?xml version = "1.0" encoding = "UTF-8"?>  
<order xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" >  
 <ship>  
    <zipcode>78712</zipcode>  
    <street>1234 Main Street</street>  
    <country>CN</country>    
    <city>Beijing</city>  
 </ship>   
 <items>     
    <quantity>1</quantity>     
    <itemno>1234</itemno>  
 </items>     
 <items>     
    <quantity>3</quantity>    
    <itemno>1235</itemno>    
 </items>    
 <price>456</price>  
 <customer>Tom Hill</customer>    
</order>  

预期输出 xml 文档如下:

<?xml version = "1.0" encoding = "UTF-8"?>  
<order xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" >  
 <customer>Tom Hill</customer>    
 <ship>  
    <street>1234 Main Street</street>  
    <city>Beijing</city>  
    <zipcode>78712</zipcode>  
    <country>CN</country>    
 </ship>    
 <items>     
    <itemno>1234</itemno>    
    <quantity>1</quantity>     
 </items>     
 <items>     
    <itemno>1235</itemno>    
    <quantity>3</quantity>    
 </items>    
 <price>456</price>  
</order> 

我使用以下 xslt 文档来翻译它。

<?xml version="1.0"?>  
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">  
<xsl:template match="/order">  
 <xsl:copy>  
  <xsl:copy-of select="customer" />  
  <xsl:copy-of select="ship" >  
  <xsl:call-template name="TShip" />  
  </xsl:copy-of>  
  <xsl:copy-of select="items">  
  <xsl:call-template name="TItems" />  
  </xsl:copy-of>  
 <xsl:copy-of select="price" />  
 </xsl:copy>  
</xsl:template>  

<xsl:template name="TShip">  
 <xsl:copy>  
  <xsl:copy-of select="street" />  
  <xsl:copy-of select="city" />  
  <xsl:copy-of select="zipcode" />  
  <xsl:copy-of select="country" />  
 </xsl:copy>  
</xsl:template>  

<xsl:template name="TItems">  
 <xsl:for-each select="items">  
  <xsl:copy>  
   <xsl:copy-of select="itemno" />  
   <xsl:copy-of select="quantity" />  
  </xsl:copy>  
 </xsl:for-each>  
</xsl:template>  

</xsl:stylesheet>  

然而翻译出来的结果并不是我所期望的。 翻译结果 xml:

<?xml version = "1.0" encoding = "UTF-8"?>  
<order xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" >  
 <customer>Tom Hill</customer>    
 <ship>  
    <zipcode>78712</zipcode>  
    <street>1234 Main Street</street>  
    <country>CN</country>    
    <city>Beijing</city>    
 </ship>    
 <items>     
    <quantity>1</quantity>     
    <itemno>1234</itemno>    
 </items>     
 <items>     
    <quantity>3</quantity>    
    <itemno>1235</itemno>   
 </items>    
 <price>456</price>  
</order>  

它只是按预期顺序创建了第一级节点。所有子节点均保持原始顺序。如何使所有节点的顺序符合我的预期?


xsl:copy-of也复制所有子节点,并且不评估其子节点。

因此,您的 TShip 和 TItems 模板甚至从未被评估。<xsl:copy-of select="ship">复制全部<ship>...</ship>.

对模板的此修改将表明您的 TShip 和 TItems 模板没有被调用。

<?xml version="1.0"?>  
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">  
<xsl:template match="/order">  
 <xsl:copy>  
  <xsl:copy-of select="customer" />
    <xsl:copy-of select="ship">
  <xsl:call-template name="TShip" />  
</xsl:copy-of>
  <xsl:copy-of select="items">  
  <xsl:call-template name="TItems" />  
  </xsl:copy-of>  
 <xsl:copy-of select="price" />  
 </xsl:copy>  
</xsl:template>  

<xsl:template name="TShip">  
 <xsl:copy>  
  <test>TShip called</test>
  <xsl:copy-of select="street" />  
  <xsl:copy-of select="city" />  
  <xsl:copy-of select="zipcode" />  
  <xsl:copy-of select="country" />  
 </xsl:copy>  
</xsl:template>  

<xsl:template name="TItems">  
 <xsl:for-each select="items">  
  <xsl:copy> 
  <test>TItems called</test>
   <xsl:copy-of select="itemno" />  
   <xsl:copy-of select="quantity" />  
  </xsl:copy>  
 </xsl:for-each>  
</xsl:template>  

</xsl:stylesheet>

请注意,输出确实not包含<test>我添加的元素。

你需要做什么是递归隐式复制。通常xsl:copy, xsl:copy-of and xsl:for-each是 xsl 模板设计不良的标志——很少有问题会导致xsl:template and xsl:apply-template使用身份转换并不能更好地处理。

我就是这样做的:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output encoding="UTF-8" indent="yes" method="xml" />

    <xsl:template match="order">
        <xsl:copy>
            <!-- copy all attributes; maybe you don't want this -->
            <xsl:apply-templates select="@*" />
            <!-- copy some elements in a specific order  -->
            <xsl:apply-templates select="customer" />
            <xsl:apply-templates select="ship" />
            <xsl:apply-templates select="items" />
            <xsl:apply-templates select="price" />
            <!-- now copy any other children that we haven't explicitly reordered; again, possibly this is not what you want -->
            <xsl:apply-templates select="*[not(self::customer or self::ship or self::items or self::price)]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ship">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="street" />
            <xsl:apply-templates select="city" />
            <xsl:apply-templates select="zipcode" />
            <xsl:apply-templates select="country" />
            <xsl:apply-templates select="*[not(self::street or self::city or self::zipcode or self::country)]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="items">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="itemno" />
            <xsl:apply-templates select="quantity" />
            <xsl:apply-templates select="*[not(self::itemno or self::quantity)]"/>
        </xsl:copy>
    </xsl:template>

    <!-- this is the identity transform: it copies everything that isn't matched by a more specific template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

请注意,此模板设计对源 XML 结构所做的假设少了多少。它也更容易更改:例如,如果您想静默或重命名本身可能有子元素的特定元素,您只需添加一个新的xsl:template与该元素匹配,做任何你需要做的事情,并且xsl:apply-templates在孩子们身上。

你应该了解有关此 XSLT 模式的更多信息因为它的用途非常广泛,可以使模板创作变得不那么繁琐,并且您的模板也不那么脆弱。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过 xslt 重新排列 xml 节点(包括子节点) 的相关文章

随机推荐