如何使用 XPath 从 XML 中检索递归元素

How to retrive recursive element from XML using XPath

在处理 Xpath 表达式时,我遇到了一种情况,我必须找出依赖于另一个节点的一个元素的节点。

下面是使用的 XML 示例:

<?xml version="1.0" encoding="UTF-8" ?>

<parent1>
    <child1 id="1">
        <in>Starting1</in>
        <out>connect1</out>
    </child1>
    <child1 id="2">
        <in>connect1</in>
        <out>connect1.1</out>
    </child1>
    <child1 id="3">
        <in>Starting2</in>
        <out>connect2</out>
    </child1>
    <child1 id="4">
        <in>connect1.1</in>
        <out>connect1.2</out>
    </child1>
    <child1 id="5">
        <in>connect1.2</in>
        <out>end1</out>
    </child1>
    <child1 id="6">
        <in>connect2</in>
        <out>connect2.1</out>
    </child1>
    <child1 id="7">
        <in>connect2.1</in>
        <out>connect2.2</out>
    </child1>
    <child1 id="8">
        <in>connect2.2</in>
        <out>open2</out>
    </child1>
</parent1>

期望的输出是找出起点为 "Starting" 的节点,然后前往另一个节点(意味着,对于其他节点,节点外是 In)并且不以 [=35 结束=].

开始和结束之间可能有 x 个连接。

我使用了以下 xpath 表达式。但这仅限于 2 级递归。

//parent1/child1[in=(//parent1/child1[in=(//parent1/child1[in=(//parent1/child1[contains(in,"Starting")]/out)]/out)]/out) and not(contains(out,"end"))]

输出:

<child1 id="8">
  <in>connect2.2</in>
  <out>open2</out>
</child1>

因为,我不确定节点之间可以有多少个连接器。那么,在XML1.0中有什么方法可以找出递归吗?

有一个 duplicate question already in Whosebug. 但是,我没有从那里得到解决方案。

//parent1/child1[包含(in/text(), 'Starting') 而不是(包含(out/text(), 'end'))]

更新

看图片。它 returns 正是您所要求的:

Desired output is to find out the node, which is having starting point as "Starting" & Not ending in "end".

你能用你的期望更新你的问题吗?也许你希望使用你添加的 XML 的输出。

你的要求不是很清楚。从我认为我理解的一点点来看,我相信你必须在两个 passes.Here 的部分示例中做到这一点:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="edge-by-in" match="child1" use="in" />
<xsl:key name="edge-by-out" match="child1" use="out" />

<xsl:template match="/parent1">
    <xsl:variable name="first-pass">
        <xsl:for-each select="child1">
            <edge id="{@id}">
                <xsl:apply-templates select="." mode="find-start"/>
                <xsl:apply-templates select="." mode="find-end"/>
            </edge>
        </xsl:for-each>
    </xsl:variable>
    <output>
        <!-- process the nodes contained in $first-pass -->
    </output>
</xsl:template>

<xsl:template match="child1" mode="find-start">
    <xsl:variable name="prev" select="key('edge-by-out', in)" />
    <xsl:choose>
        <xsl:when test="$prev">
            <xsl:apply-templates select="$prev" mode="find-start"/>
        </xsl:when>
        <xsl:otherwise>
            <start>
                <xsl:value-of select="in"/>
            </start>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="child1" mode="find-end">
    <xsl:variable name="next" select="key('edge-by-in', out)" />
    <xsl:choose>
        <xsl:when test="$next">
            <xsl:apply-templates select="$next" mode="find-end"/>
        </xsl:when>
        <xsl:otherwise>
            <end>
                <xsl:value-of select="out"/>
            </end>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

当您将此应用于您的输入时,$first-pass 变量将包含:

   <edge id="1">
      <start>Starting1</start>
      <end>end1</end>
   </edge>
   <edge id="2">
      <start>Starting1</start>
      <end>end1</end>
   </edge>
   <edge id="3">
      <start>Starting2</start>
      <end>open2</end>
   </edge>
   <edge id="4">
      <start>Starting1</start>
      <end>end1</end>
   </edge>
   <edge id="5">
      <start>Starting1</start>
      <end>end1</end>
   </edge>
   <edge id="6">
      <start>Starting2</start>
      <end>open2</end>
   </edge>
   <edge id="7">
      <start>Starting2</start>
      <end>open2</end>
   </edge>
   <edge id="8">
      <start>Starting2</start>
      <end>open2</end>
   </edge>

现在您可以将其用于 select 个具有(或不具有)特定 startend 的节点。