XSLT: найти номер данного узла - PullRequest
2 голосов
/ 08 сентября 2011

У меня есть структура XML, представляющая логическое деривация, и она выглядит так:

<derivation>
  <step name="foo">
    <derive>[...]</derive>
    <by>[...]</by>
  </step>
  <step name="bar">
    <derive>[...]</derive>
    <by>
      <from name="foo"/>, conjunction elimination
    </by>
  </step>
  <step name="baz">
    <derive>[...]</derive>
    <by>
      <from name="bar"/>, existential quantification
    </by>
  </step>
  [...]
</derivation>

Каждый <step> в деривации имеет номер - например, что с name="foo" будетчисло 1, которое с name="bar" будет числом 2, что с name="baz" будет числом 3 и так далее.Находясь внутри <step>, я могу найти номер с <xsl:number/>.Пока все хорошо.

Теперь, , где встречается элемент <from name="bar"/>, я хочу, чтобы он был заменен номером элемента <step> на name="bar".Здесь нужно решить три подзадачи:

  • Найти самого последнего предка элемента <from>, который является <derivation>.
  • Из этого найдите первого потомка, который<step> элемент с name="bar".В приведенном выше примере это будет второй дочерний элемент <derivation>.
  • Идентифицирует номер этого элемента.В приведенном выше примере это будет 2.

Может ли кто-нибудь связать воедино решения этих подзадач, чтобы удовлетворить мое требование?

Ответы [ 4 ]

2 голосов
/ 08 сентября 2011

Это преобразование :

<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()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="from[@name]">
  <xsl:variable name="vReferred" select=
    "ancestor::derivation[1]/step[@name = current()/@name]"/>

   <xsl:for-each select="$vReferred">
     <xsl:number count="step" level="any"/>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному XML-документу :

<derivation>
    <step name="foo">
        <derive>[...]</derive>
        <by>[...]</by>
    </step>
    <step name="bar">
        <derive>[...]</derive>
        <by>
            <from name="foo"/>, conjunction elimination     
        </by>
    </step>
    <step name="baz">
        <derive>[...]</derive>
        <by>
            <from name="bar"/>, existential quantification     
        </by>
    </step>   [...] 
</derivation>

создает искомое, правильный результат :

<derivation>
   <step name="foo">
      <derive>[...]</derive>
      <by>[...]</by>
   </step>
   <step name="bar">
      <derive>[...]</derive>
      <by>1, conjunction elimination     
        </by>
   </step>
   <step name="baz">
      <derive>[...]</derive>
      <by>2, existential quantification     
        </by>
   </step>   [...] 
</derivation>
1 голос
/ 08 сентября 2011

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

<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:key name="kStepByName" match="derivation/step"
         use="@name"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="from[@name]">
  <xsl:variable name="vReferred" select=
    "key('kStepByName',@name)"/>

   <xsl:for-each select="$vReferred">
     <xsl:number count="step" level="any"/>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>
1 голос
/ 08 сентября 2011

Fun с осями XPath ...

count(ancestor::derivation/step[@name=$name]/preceding-sibling::step)+1

Это захватывает ближайшего предка, являющегося производным, получает дочерний шаг с правильным именем, а затем получает всех предшествующих братьев и сестер с именем step.Он считает их и добавляет 1 (поскольку шаг 2 будет иметь 1 предшествующий брат).

ссылка на ось XPath

0 голосов
/ 08 сентября 2011

Хотя оба решения уже опубликованы, все в порядке, просто для справки я добавляю другое возможное решение.

Что-то вроде:

<xsl:template match="from">
  <xsl:variable name="ref" select="@name"/>
  <xsl:apply-templates mode="number" select="ancestor::derivation/step">
    <xsl:with-param name="ref" select="$ref"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template name="step" mode="number">
  <xsl:param name="ref"/>
  <xsl:if test="@name=$ref">
    Item no. <xsl:value-of select="position()"/>
  </xsl:if>
</xsl:template>

Обратите внимание, что я неПишу XSLT уже несколько лет, хотя идея этого решения должна быть правильной, синтаксис может быть совершенно неверным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...