如何使用 xslt 更改单个标签?
Posted
技术标签:
【中文标题】如何使用 xslt 更改单个标签?【英文标题】:How to change a single tag with xslt? 【发布时间】:2020-10-09 11:21:52 【问题描述】:在下面的结果中,OrderDetail
已替换为 baz
。类似的xslt
将如何仅更改OrderDetail
的第一次出现而没有其他出现?
使用saxonb-xslt
当前结果:
<?xml version="1.0" encoding="UTF-8"?>
<Order OrderID="10613">
<CustomerID>HILAA</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1997-07-29T05:38:16</OrderDate>
<RequiredDate>1997-08-26T11:38:15</RequiredDate>
<ShippedDate>1997-08-01T12:46:12</ShippedDate>
<ShipVia>2</ShipVia>
<Freight>8.1100</Freight>
<ShipName>HILARION-Abastos</ShipName>
<ShipAddress>Carrera 22 con Ave. Carlos Soublette #8-35</ShipAddress>
<ShipCity>San Cristóbal</ShipCity>
<ShipRegion>Táchira</ShipRegion>
<ShipPostalCode>5022</ShipPostalCode>
<ShipCountry>Venezuela</ShipCountry>
<OrderDetails>
<baz>
<ProductID>13</ProductID>
<UnitPrice>6.0000</UnitPrice>
<Quantity>8</Quantity>
<Discount>0.1</Discount>
</baz>
<baz>
<ProductID>75</ProductID>
<UnitPrice>7.7500</UnitPrice>
<Quantity>40</Quantity>
<Discount>0</Discount>
</baz>
</OrderDetails>
</Order>
来自这个snippet 的一个更大的xml
文件:
<Order OrderID="10613">
<CustomerID>HILAA</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1997-07-29T05:38:16</OrderDate>
<RequiredDate>1997-08-26T11:38:15</RequiredDate>
<ShippedDate>1997-08-01T12:46:12</ShippedDate>
<ShipVia>2</ShipVia>
<Freight>8.1100</Freight>
<ShipName>HILARION-Abastos</ShipName>
<ShipAddress>Carrera 22 con Ave. Carlos Soublette #8-35</ShipAddress>
<ShipCity>San Cristóbal</ShipCity>
<ShipRegion>Táchira</ShipRegion>
<ShipPostalCode>5022</ShipPostalCode>
<ShipCountry>Venezuela</ShipCountry>
<OrderDetails>
<OrderDetail>
<ProductID>13</ProductID>
<UnitPrice>6.0000</UnitPrice>
<Quantity>8</Quantity>
<Discount>0.1</Discount>
</OrderDetail>
<OrderDetail>
<ProductID>75</ProductID>
<UnitPrice>7.7500</UnitPrice>
<Quantity>40</Quantity>
<Discount>0</Discount>
</OrderDetail>
</OrderDetails>
</Order>
使用此xslt
转换:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="OrderDetail">
<baz>
<xsl:apply-templates/>
</baz>
</xsl:template>
</xsl:stylesheet>
但是,这会更改所有匹配的节点名称。
【问题讨论】:
【参考方案1】:第一个<OrderDetail>
是前面没有<OrderDetail>
s 的那个。
<xsl:template match="OrderDetail[not(preceding::OrderDetail)]">
<baz>
<xsl:apply-templates/>
</baz>
</xsl:template>
这匹配整个文档中的第一个,不管嵌套。
根据您如何定义“第一”,还有其他选项,例如match="OrderDetail[1]"
,匹配其各自父元素中的第一个。
【讨论】:
和match
在 xslt 3 但不是 2?而且,是的,我可能将“第一”定义为更多 OrderDetail[1]
与某种相对 xpath (?)。
@NicholasSaunders "match
在 xslt 3 中但不在 2 中?" - match
一直都在,不知道你的意思。 "sort of relative xpath (?)" 也不清楚。你能详细说明一下吗?
我的误解,然后我认为match
对xslt
3 来说是新的。就OrderDetail
在树中的位置而言,这个问题有些模糊:哪个节点是它的父节点等。使用not(proceeding()
肯定是有道理的。
@Nicholas 匹配表达式可以指定树中的位置,但它不需要。如果只给出match="OrderDetail[1]"
,则匹配任何元素中的任何第一个<OrderDetail>
。如果给定"OrderDetails/OrderDetail[1]"
,则匹配任何<OrderDetails>
中的任何第一个<OrderDetail>
,但它不会假设<OrderDetails>
的位置。等等。这确实与其他地方的 XPath 不同,后者总是引用上下文元素,除非它是绝对路径。以上是关于如何使用 xslt 更改单个标签?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 XSLT 将单个子 xml 元素转换为 Json 数组