gpt4 book ai didi

xml - 通过 xslt 重新排列 xml 节点,包括子节点

转载 作者:数据小太阳 更新时间:2023-10-29 01:53:51 25 4
gpt4 key购买 nike

我有一个 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>

注意输出包含<test>我添加的元素。

您需要做的是递归隐式复制。通常xsl:copy , xsl:copy-ofxsl:for-each是糟糕的 xsl 模板设计的标志——很少有问题 xsl:templatexsl: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 结构的假设减少了多少。它也更容易改变:例如,如果你想沉默或重命名一个可能本身有 child 的特定元素,你只需添加一个新的 xsl:template匹配那个元素,做任何你需要做的,然后 xsl:apply-templates在 children 身上。

你应该 learn more about this XSLT pattern 因为它用途广泛,使模板创作变得不那么乏味,您的模板也不那么脆弱。

关于xml - 通过 xslt 重新排列 xml 节点,包括子节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8305258/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com