Найти предыдущие / следующие элементы в документе, используя XSLT / XPath - PullRequest
1 голос
/ 17 сентября 2011

Я не могу придумать простой и элегантный способ поиска «предыдущих» и «следующих» элементов в документе XML с использованием XPath или простого шаблона XSLT.Вот пример XML-документа (в реальном документе @id не будет упорядочен так просто)

<manual>
  <section id="1">
    <section id="2">
      <section id="3"/>
      <section id="4"/>
      <section id="5"/>
    </section>
    <section id="6">
      <section id="7"/>
      <section id="8"/>
      <section id="9"/>
    </section>
  </section>
  <section id="10"/>
  <section id="11">
    <section id="12"/>
  </section>
</manual>

А вот что я имею в виду под предыдущим / последующим в порядке документов

+------------------+------------------+--------------+
| Selected section | Previous section | Next section |
+------------------+------------------+--------------+
| 1                | none             | 2            |
| 2                | 1                | 3            |
| 3                | 2                | 4            |
| 4                | 3                | 5            |
| 5                | 4                | 6            |
| ...              | ...              | ...          |
| 10               | 9                | 11           |
| 11               | 10               | 12           |
| 12               | 11               | none         |
+------------------+------------------+--------------+

Проблема с осью preceding:: заключается в том, что предки исключаются, т. Е. section[id=2] не является предшествующим узлом section[id=3].

Таким же образом, ось following:: исключаетпотомки, то есть section[id=3] не является следующим узлом для section[id=2].

Итак, как я могу создать «предыдущий» и «следующий» элементы, например, из этих шаблонов:

<xsl:template match="section" mode="prev">
  <xsl:value-of select="... what to put here ..."/>
</xsl:template>

<xsl:template match="section" mode="next">
  <xsl:value-of select="... what to put here ..."/>
</xsl:template>

Примечаниеэто аналогичный, но не тот же вопрос: XPath 1.0, ближайший предшествующий узел и / или узел-предок с атрибутом в дереве XML .Эти конструкции XPath действительно у меня над головой, иногда ...

Ответы [ 2 ]

1 голос
/ 17 сентября 2011

Вот таблица стилей, которая включает в себя предложение Николаса с союзом, затем берется last() для предыдущего элемента и первое для следующего элемента:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">

  <xsl:output method="html" indent="yes"/>

  <xsl:template match="manual">
    <table>
      <thead>
        <tr>
          <th>Selected section</th>
          <th>Previous section</th>
          <th>Next section</th>
        </tr>
      </thead>
      <tbody>
        <xsl:apply-templates select="descendant::section"/>
      </tbody>
    </table>
  </xsl:template>

  <xsl:template match="section">
    <tr>
      <td>
        <xsl:value-of select="@id"/>
      </td>
      <xsl:apply-templates select="." mode="prev"/>
      <xsl:apply-templates select="." mode="next"/>
    </tr>
  </xsl:template>

  <xsl:template match="section" mode="prev">
    <td>
      <xsl:value-of select="(preceding::section | ancestor::section)[last()]/@id"/>
    </td>
  </xsl:template>

  <xsl:template match="section" mode="next">
    <td>
      <xsl:value-of select="(following::section | descendant::section)[1]/@id"/>
    </td>
  </xsl:template>

</xsl:stylesheet>

С вашим входом семпла Saxon 6.5.5

<table>
   <thead>
      <tr>
         <th>Selected section</th>
         <th>Previous section</th>
         <th>Next section</th>
      </tr>
   </thead>
   <tbody>
      <tr>
         <td>1</td>
         <td></td>
         <td>2</td>
      </tr>
      <tr>
         <td>2</td>
         <td>1</td>
         <td>3</td>
      </tr>
      <tr>
         <td>3</td>
         <td>1</td>
         <td>4</td>
      </tr>
      <tr>
         <td>4</td>
         <td>1</td>
         <td>5</td>
      </tr>
      <tr>
         <td>5</td>
         <td>1</td>
         <td>6</td>
      </tr>
      <tr>
         <td>6</td>
         <td>1</td>
         <td>7</td>
      </tr>
      <tr>
         <td>7</td>
         <td>1</td>
         <td>8</td>
      </tr>
      <tr>
         <td>8</td>
         <td>1</td>
         <td>9</td>
      </tr>
      <tr>
         <td>9</td>
         <td>1</td>
         <td>10</td>
      </tr>
      <tr>
         <td>10</td>
         <td>1</td>
         <td>11</td>
      </tr>
      <tr>
         <td>11</td>
         <td>1</td>
         <td>12</td>
      </tr>
      <tr>
         <td>12</td>
         <td>1</td>
         <td></td>
      </tr>
   </tbody>
</table>
0 голосов
/ 17 сентября 2011

"Не очень элегантная" реализация была бы такой (выбирая @id, а не весь узел)

<xsl:template match="section" mode="prev-id">
  <xsl:variable name="id" select="@id"/>

  <xsl:variable name="position">
    <xsl:for-each select="//section">
      <xsl:if test="@id = $id">
        <xsl:value-of select="position()"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:for-each select="//section">
    <xsl:if test="position() = $position - 1">
      <xsl:value-of select="@id"/>
    </xsl:if>
  </xsl:for-each>
</xsl:template>

<xsl:template match="section" mode="next-id">
  <xsl:variable name="id" select="@id"/>

  <xsl:variable name="position">
    <xsl:for-each select="//section">
      <xsl:if test="@id = $id">
        <xsl:value-of select="position()"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:for-each select="//section">
    <xsl:if test="position() = $position + 1">
      <xsl:value-of select="@id"/>
    </xsl:if>
  </xsl:for-each>
</xsl:template>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...