Xml XSLT:删除子节点而不重复XPath
我有以下XML:Xml XSLT:删除子节点而不重复XPath,xml,xslt,xpath,Xml,Xslt,Xpath,我有以下XML: <?xml version="1.0"?> <Transaction> <Product> <ProductRq> <ContactInfo> <!-- several child elements --> </ContactInfo> <OrderInfo>
<?xml version="1.0"?>
<Transaction>
<Product>
<ProductRq>
<ContactInfo>
<!-- several child elements -->
</ContactInfo>
<OrderInfo>
<!-- several child elements -->
</OrderInfo>
<ProductInfo>
<!-- several child elements -->
</ProductInfo>
<AddressInfo>
<!-- several child elements -->
</AddressInfo>
<AuditInfo>
<!-- several child elements -->
</AuditInfo>
<DeliveryInfo>
<!-- several child elements -->
</DeliveryInfo>
</ProductRq>
</Product>
</Transaction>
为简洁起见,我省略了
标记的几个子元素,该标记包含4个或5个类似于
和
的子元素,以及*Info元素的子节点
我需要删除Order和
等元素的子元素,同时保留*Info标记。在7个标签中,大约有4个需要通过这个过程。我想不出如何做到这一点而不重复:
<xsl:template match="Transcation/Product/ProductRq/<tag name here>/*" />
对于
的每个子级。有没有一种方法可以利用上下文节点(
)并通过子节点进行循环,除去上面提到的子节点之外,删除它们自己的子节点
编辑:我添加了
的剩余子标记。除
和
之外的所有标记都必须删除其子节点。一种解决方案是应用以下XSLT:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<!-- identity transform -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<!-- skip all child nodes of ProductRq except they are AuditInfo or ContactInfo -->
<xsl:template match="ProductRq/*[not(self::AuditInfo | self::ContactInfo)]">
<xsl:element name="{name(.)}" /> <!-- so create an element with this name -->
</xsl:template>
</xsl:stylesheet>
输出:
<?xml version="1.0"?>
<Transaction>
<Product>
<ProductRq>
<ContactInfo>
<!-- several child elements -->
</ContactInfo>
<OrderInfo/>
<ProductInfo/>
<AddressInfo/>
<AuditInfo>
<!-- several child elements -->
</AuditInfo>
<DeliveryInfo/>
</ProductRq>
</Product>
</Transaction>
我需要删除元素的子元素,如Order
和
同时保留*Info标记
您正在寻找的模板是
<!-- XSLT 2.0 and up -->
<xsl:template match="ProductRq/*[ends-with(name(), 'Info')]/*" />
<!-- XSLT 1.0 variant, as ends-with() does not exist here -->
<xsl:template match="ProductRq/*[
substring-before(name(), 'Info') != '' and substring-after(name(), 'Info') = ''
]/*" />
编写一个与
ProductRq
匹配的模板:
<xsl:template match="ProductRq">
<xsl:copy>
<xsl:apply-templates select="ContactInfo | OrderInfo | ProductInfo | AddressInfo"/>
</xsl:copy>
</xsl:template>
综上所述,您可以在两个位置写入相关节点的名称(以“|”分隔):
- 所有名称都是第一个模板
- 要在第二个模板中浅复制的节点的名称
无论如何,您必须在某个地方编写这些名称。您实际上不需要在模板匹配中指定完整的xpath,只需执行
。如果同一元素可能出现在层次结构中的不同级别,并且需要区分它们,那么您只需要使用完整路径对其进行限定。我认为ProductRq的一些子元素可能会在文档更深处的不同标记中重复,但ProducerRq是唯一的,那么ProducerRq/就足够了?@jbailie1991-你真的需要展示那些遗漏的孩子,因为他们与你的问题非常相关。至少显示ProductRq的子元素。我喜欢XSLT2单行程序,但这会删除以Info结尾的所有元素的所有子元素。对于我的用例,我需要保留AuditInfo和ContactInfo的子元素,并去掉其他*信息的子节点tags@jbailie1991这很简单,只需将异常添加到表达式中,如而不是(name()=“KeepThis”或name()=“KeepThis”)
@jbailie1991关于我的答案有什么反馈吗?你还试过吗?它起作用了吗?如果没有,什么不起作用?我同意上面的答案。它允许我剥离ProductRq子元素的子元素,而不删除实际的子元素本身,同时跳过问题中概述的异常,而这将删除所有子元素,即使使用您发布的添加异常的方法,它仍然会完全删除标记,而不是删除子元素的子元素,但保留空标记。因此,如果我理解正确,第三个模板会匹配ProductRq中不是AuditInfo或ContactInfo的子节点,然后检查元素名称是否为空,如果不是,是否创建具有该名称的新元素?所以或多或少地用相同的标记覆盖匹配的元素,除了它是空的吗?@jbailie1991:你说得对。在阅读了你的评论之后,我也从答案中删除了多余的第二个模板。所以最后一个(前3个)模板只是重新创建了所有元素,这些元素不是AuditInfo
或ContactInfo
(并且不是其他节点类型(name()=empty)),没有任何子节点。啊,好的,这很酷。因此,即使这些子节点为空,这些子节点也会一直存在,所以这可以进一步删除条件吗?只需将找到的每个元素替换为一个空白版本?@jbailie1991:我进一步改进了我的答案,将ProductRq/node()[…]
替换为ProductRq/*[…]
。这样,只选择了元素(而不是所有节点),因此我看到了,因此我将在第一个模板中指定所有ProductRqs子节点,并定义我希望在第二个模板中从哪些节点剥离子节点?另外,空标签,这些是下游系统的标签。我并不是百分之百地理解他们为什么希望xml中有一个,但我猜这是为了进行额外的处理(可能是验证;我的服务不需要这样做),因为它位于两个队列之间,它的唯一任务是根据附加到Exchange对象的头为其他系统转换xml
<xsl:template match="ContactInfo | OrderInfo">
<xsl:copy><xsl:apply-templates select="text()"/></xsl:copy>
</xsl:template>