XPath 1.0在XML树中具有属性的最接近的前一个和/或祖先节点

XPath 1.0在XML树中具有属性的最接近的前一个和/或祖先节点,xml,xslt,xpath,Xml,Xslt,Xpath,下面是三个XML树 (一) (二) 在这两种情况下,理想的结果都是id5 使用XSLT1.0和XPath1.0,我可以从(1)中获取祖先 或(2)中的前一个节点 如何使用书签中的id获取最近的祖先或前面的节点? 我需要一个xsl:value,它匹配两种情况。谢谢 编辑: 解决方案还应涵盖此结构。所需id仍然为5 (三) 试试: <xsl:value-of select="//bookmark/ancestor::*[1]/descendant-or-self::

下面是三个XML树

(一)


(二)


在这两种情况下,理想的结果都是id5

使用XSLT1.0和XPath1.0,我可以从(1)中获取祖先


或(2)中的前一个节点


如何使用书签中的id获取最近的祖先或前面的节点?
我需要一个xsl:value,它匹配两种情况。谢谢

编辑:

解决方案还应涵盖此结构。所需id仍然为5

(三)


试试:

<xsl:value-of 
    select="//bookmark/ancestor::*[1]/descendant-or-self::*[last()-1]/@id"/>
另一个普遍解决办法:

<xsl:for-each
    select="//section[following::bookmark or descendant::bookmark][@id]">
    <xsl:if test="position() = last()">
        <xsl:value-of select="./@id"/>
    </xsl:if>
</xsl:for-each>

使用

    (//bookmark/ancestor::*[@id][1]/@id 
| 
    //bookmark/preceding::*[@id][1]/@id
     )
     [last()]
验证:使用XSLT作为XPath主机,进行以下转换:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:value-of select=
  "(//bookmark/ancestor::*[@id][1]/@id
  |
   //bookmark/preceding::*[@id][1]/@id
   )
    [last()]"/>
 </xsl:template>
</xsl:stylesheet>

当应用于提供的三个XML文档中的任何一个时,会生成所需的正确结果

    (//bookmark/ancestor::*[@id][1]/@id 
| 
    //bookmark/preceding::*[@id][1]/@id
     )
     [last()]
5


我强烈建议使用用于玩/学习XPath的

您的解决方案在特殊情况下有效。但如果我在两个XML上的书签后添加更多id为的节,您的解决方案将给出错误的结果。将编辑我的示例,使其在书签后有一些部分。@therealmarv:对。我假设了具体的结构。检查我的第二个解决方案。@Therelmarv:corrected
last()
1
lastSibling
变量中。您的解决方案是一个很好的方法。它给了我一些想法。但这不是一个普遍的解决办法。我再次编辑了我的示例。最近的祖先可能不是父节点,id可能位于前一个节点的子节点的某个位置。哇。您更通用的解决方案适用于(1)和(3)。非常感谢!:-)但是,它不适用于(2),解决方案为空。还在弄清楚原因是什么。希望我能解决显示所有xpath轴的itPicture:好问题,+1。请参阅我的答案,了解一行XPath表达式,该表达式在所有三种情况下都精确地选择所需的属性节点。:)
<xsl:value-of 
    select="//bookmark/ancestor::*[1]/descendant-or-self::*[last()-1]/@id"/>
<xsl:variable name="lastSibling"
    select="//bookmark/preceding-sibling::*[1]"/>
<xsl:choose>
    <xsl:when test="$lastSibling">
        <xsl:value-of
            select="$lastSibling/descendant-or-self::*[last()]/@id"/>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="//bookmark/ancestor::*[@id][1]/@id"/>
    </xsl:otherwise>
</xsl:choose>
<xsl:for-each
    select="//section[following::bookmark or descendant::bookmark][@id]">
    <xsl:if test="position() = last()">
        <xsl:value-of select="./@id"/>
    </xsl:if>
</xsl:for-each>
    (//bookmark/ancestor::*[@id][1]/@id 
| 
    //bookmark/preceding::*[@id][1]/@id
     )
     [last()]
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:value-of select=
  "(//bookmark/ancestor::*[@id][1]/@id
  |
   //bookmark/preceding::*[@id][1]/@id
   )
    [last()]"/>
 </xsl:template>
</xsl:stylesheet>