Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSLT:删除子节点而不重复XPath_Xml_Xslt_Xpath - Fatal编程技术网

Xml XSLT:删除子节点而不重复XPath

Xml XSLT:删除子节点而不重复XPath,xml,xslt,xpath,Xml,Xslt,Xpath,我有以下XML: <?xml version="1.0"?> <Transaction> <Product> <ProductRq> <ContactInfo> <!-- several child elements --> </ContactInfo> <OrderInfo>

我有以下XML:

<?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>