Функция XSLT для получения xpath к узлу - PullRequest
2 голосов
/ 14 декабря 2011

Мне нужна функция XSLT, которая вернет мне xpath к узлу, из которого она была вызвана

XML

    <root>
      <node>
        <subnode />
        <subnode />
        <subnode />
      </node>
      <node>
        <subnode>
          <subsubnode >
            <xsl:value-of select="fn:generateXPath()" />
          </subsubnode >
        </subnode>
      </node>
    </root>

XSL

    <xsl:template match="root/node/subnode/sub" >
        <xsl:value-of select="fn:generateXPath()" />
    </xsl:template>

    <xsl:function name="fn:generateXPath" >
      <xsl:for-each select="ancestor::*">
      <xsl:value-of select="name()" />
      </xsl:for-each>
      <xsl:value-of select="name()" /> 
    </xsl:function>

Я пытался использовать вышеуказанную функцию, но выдает ошибку:

XPDY0002: здесь невозможно выбрать узел: элемент контекста не определен

Но когда я попробовал это в именованном шаблоне, я смог получить результат. Может ли это быть реализовано с помощью xslt:function.

Ответы [ 2 ]

4 голосов
/ 14 декабря 2011

Я пытался использовать вышеуказанную функцию, но выдает ошибку:

XPDY0002: Cannot select a node here: the context item is undefined

Но когда я попробовал это в названном шаблоне, я смог получить результат.

Согласно спецификации W3C XSLT 2.0:

" В теле функции таблицы стилей фокус изначально не определено; это означает, что любая попытка сослаться на элемент контекста, позиция контекста или размер контекста является невосстановимой динамической ошибкой . [XPDY0002] "

В вашем коде:

<xsl:function name="fn:generateXPath" >    
  <xsl:for-each select="ancestor::*">    
  <xsl:value-of select="name()" />    
  </xsl:for-each>    
  <xsl:value-of select="name()" />     
</xsl:function>    

существует ряд относительных выражений, которые могут быть оценены только относительно элемента контекста (фокус, текущий узел), однако такого определения не существует по определению (см. Цитату выше), и таким образом вы получаете сообщенная ошибка.

Решение

Добавьте параметр для этой функции - естественно, что это будет узел, XPath для выбора которого требуется:

<xsl:function name="fn:generateXPath" as="xs:string" >
  <xsl:param name="pNode" as="node()"/>

  <xsl:for-each select="$pNode/ancestor::*">    
    <xsl:value-of select="name()" />    
  </xsl:for-each>    
  <xsl:value-of select="name($pNode)" />     
</xsl:function>    

и вызвать эту функцию следующим образом:

fn:generateXPath(someNode)

Примечание : Очевидно, вам необходимо объединить каждое имя в символ "/", а также сузить выражение, чтобы не выбирать какие-либо узлы узла, используя позиции в предикатах. Полное и правильное решение, которое создает выражение XPath для узла, см. В моем ответе на этот вопрос: https://stackoverflow.com/a/4747858/36305

3 голосов
/ 14 декабря 2011

Одной из причин отсутствия стандартной функции является то, что люди хотят путь по разным причинам:

Иногда a/b/c/d достаточно.

Некоторые люди хотят a[3]/b[5]/c[1]/d[2].

Некоторым людям нужен путь, в котором имена не содержат префиксов пространства имен, поэтому это должно быть что-то вроде

*:a[namespace-uri()='abc']/*:b[namespace-uri='xyz'] и т. Д.

...