Функция XSLT для получения xpath к узлу

Мне нужна функция 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.


person rohit    schedule 14.12.2011    source источник


Ответы (2)


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

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

person Dimitre Novatchev    schedule 14.12.2011
comment
Также обратите внимание на полезное сокращение <xsl:value-of select="$pNode/ancestor::*/name()" separator="/"/> - person Michael Kay; 14.12.2011
comment
@MichaelKay: Да, я бы так и поступил. Здесь я просто добавил необходимые изменения, не углубляясь в код ОП. - person Dimitre Novatchev; 14.12.2011
comment
Я назначаю возврат переменной. И мне нужно получить значение из другого XML той же схемы. Для этого я попробовал ‹xsl: variable name = LookUpXml select = document ('sample2.xml') /› ‹xsl: value-of select = $ LookUpXml / saxon: оценить ($ nodePath) /›. Но это дает мне ошибку, XPTY0004: последовательность из более чем одного элемента не допускается в качестве первого аргумента saxon: Assessment (). - person rohit; 15.12.2011

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

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

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

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

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

person Michael Kay    schedule 14.12.2011