从部分XPath获取完整的XPath

3
我正在使用Perl的Selenium,页面上有一个标签,我想要访问这个标签,所以我使用了以下XPath://*[text()='some here'],但问题是我需要获取该元素的完整XPath,例如:/html/body/table/tr/..../any other/and other/,是否有任何Selenium方法或Perl函数? 我正在寻找Perl解决方案或其他有效方法。谢谢。

好问题,+1。请查看我的答案,其中包含一个通用的XSLT 1.0模板,可为任何类型的节点生成XPath表达式。 - Dimitre Novatchev
2个回答

1
寻找Perl解决方案或其他可行的方法。
此XPath 2.0表达式:
string-join(for $node in ancestor-or-self::node()
            return concat(('@')[$node/self::attribute()],
                          $node/name(),
                          (concat('[',
                                  count($node/preceding-sibling::node()
                                           [name()=$node/name()]) + 1,
                                  ']'))[$node/../node()
                                           [name()=$node/name()][2]]),
            '/')

编辑:简短表达。


1

这个XSLT 1.0转换为$pNode参数中包含的每个节点生成一个XPath表达式:

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

 <xsl:template match="node()|@*">
  <path>
    <xsl:call-template name="buildPath"/>
  </path>
  <xsl:apply-templates select="node()|@*"/>
 </xsl:template>


<xsl:template name="buildPath">
 <xsl:variable name="pNode" select="."/>
  <xsl:variable name="theResult">
    <xsl:for-each select="$pNode">
    <xsl:variable name="theNode" select="."/>
    <xsl:for-each select=
    "$theNode
    |
     $theNode/ancestor-or-self::node()[..]">
      <xsl:element name="slash">/</xsl:element>
      <xsl:choose>
        <xsl:when test="self::*">
          <xsl:element name="nodeName">
            <xsl:value-of select="name()"/>
            <xsl:variable name="thisPosition" select=
            "count(preceding-sibling::*
                   [name(current())
                   =
                    name()])"/>
            <xsl:variable name="numFollowing" select=
             "count(following-sibling::
                     *[name(current())
                     =
                       name()])"/>
            <xsl:if test="$thisPosition + $numFollowing > 0">
              <xsl:value-of select=
              "concat('[', $thisPosition +1, ']')"/>
            </xsl:if>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise> <!-- This node is not an element -->
          <xsl:choose>
            <xsl:when test="count(. | ../@*) = count(../@*)">
            <!-- Attribute -->
              <xsl:element name="nodeName">
                <xsl:value-of select="concat('@',name())"/>
              </xsl:element>
            </xsl:when>
            <xsl:when test="self::text()">  <!-- Text -->
              <xsl:element name="nodeName">
                <xsl:value-of select="'text()'"/>
                <xsl:variable name="thisPosition"
                          select="count(preceding-sibling::text())"/>
                <xsl:variable name="numFollowing"
                          select="count(following-sibling::text())"/>
                <xsl:if test="$thisPosition + $numFollowing > 0">
                  <xsl:value-of select=
                  "concat('[', $thisPosition +1, ']')"/>
                </xsl:if>
              </xsl:element>
            </xsl:when>
            <xsl:when test="self::processing-instruction()">
            <!-- Processing Instruction -->
              <xsl:element name="nodeName">
                <xsl:value-of select="'processing-instruction()'"/>
                <xsl:variable name="thisPosition"
                   select="count(preceding-sibling::processing-instruction())"/>
                <xsl:variable name="numFollowing"
                    select="count(following-sibling::processing-instruction())"/>
                <xsl:if test="$thisPosition + $numFollowing > 0">
                  <xsl:value-of select=
                  "concat('[', $thisPosition +1, ']')"/>
                </xsl:if>
              </xsl:element>
            </xsl:when>
            <xsl:when test="self::comment()">   <!-- Comment -->
              <xsl:element name="nodeName">
                <xsl:value-of select="'comment()'"/>
                <xsl:variable name="thisPosition"
                         select="count(preceding-sibling::comment())"/>
                <xsl:variable name="numFollowing"
                         select="count(following-sibling::comment())"/>
                <xsl:if test="$thisPosition + $numFollowing > 0">
                  <xsl:value-of select=
                  "concat('[', $thisPosition +1, ']')"/>
                </xsl:if>
              </xsl:element>
            </xsl:when>
            <!-- Namespace: -->
            <xsl:when test=
              "count(. | ../namespace::*)
              =
               count(../namespace::*)">

              <xsl:variable name="apos">'</xsl:variable>
              <xsl:element name="nodeName">
                <xsl:value-of select="concat('namespace::*',
                '[local-name() = ', $apos, local-name(), $apos, ']')"/>

              </xsl:element>
            </xsl:when>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
    <!-- <xsl:text>&#xA;</xsl:text> -->
  </xsl:for-each>
 </xsl:variable>
 <xsl:value-of select="$theResult"/>
</xsl:template>
</xsl:stylesheet>

应用于以下XML文档时:
<div id="entry-1" class="item-asset asset hentry">
  <div class="asset-header">
    <h2 class="asset-name entry-title">
      <a rel="bookmark" href="http://blahblah.com/paper-scissors">Paper Scissors</a>
    </h2>
  </div>
  <div class="asset-content entry-content">
    <div class="asset-body">
     <p>Paper and scissors</p>
    </div>
  </div>
</div>

结果是文档中每个节点的XPath表达式列表:

<path>/div</path>
<path>/div/@id</path>
<path>/div/@class</path>
<path>/div/div[1]</path>
<path>/div/div[1]/@class</path>
<path>/div/div[1]/h2</path>
<path>/div/div[1]/h2/@class</path>
<path>/div/div[1]/h2/a</path>
<path>/div/div[1]/h2/a/@rel</path>
<path>/div/div[1]/h2/a/@href</path>
<path>/div/div[1]/h2/a/text()</path>
<path>/div/div[2]</path>
<path>/div/div[2]/@class</path>
<path>/div/div[2]/div</path>
<path>/div/div[2]/div/@class</path>
<path>/div/div[2]/div/p</path>
<path>/div/div[2]/div/p/text()</path>

那么,如何使用这个 XSLT 1.0 呢? - CODERED
@CODERED:你可以在代码中随时使用buildPath模板,并传入任何参数(节点)以获取路径。只需使用<xsl:call-template>指令即可。例如,你可以将第一个表达式选择的节点作为参数传递给buildPath的调用。 - Dimitre Novatchev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接