Порядок и дедупликация данных в атрибутах - PullRequest
0 голосов
/ 06 февраля 2012

Каждый <leg> записывает этап поездки. Поездка записывается в порядке документов. Некоторые ноги начинаются и заканчиваются в одном и том же месте (например, от МА до МА), некоторые переходят из одного места в другое (например, от МА к КТ). Некоторые данные о начальной и конечной локациях отсутствуют.

<trip>
  <leg start="MA" stop="MA" />
  <leg start="MA" stop="CT" /> 
  <leg start="NY"           />
  <leg                      />
  <leg start="DE"           />
  <leg            stop="DE" />
  <leg start="NY" stop="PA" />
</trip>

Используя XSLT / XPATH 1.0, я хочу получить список мест в порядке посещения:

<trip>
  <place>MA</place>
  <place>CT</place>
  <place>NY</place>
  <place>DE</place>
  <place>NY</place>
  <place>PA</place>
</trip>

Edit:

ОК, думаю, я вижу, как это сделать:

<xsl:template match="leg" mode="tour">
    <xsl:if test="string(@start)">
        <place><xsl:value-of select="@start"></place>
    </xsl:if>
    <xsl:if test="string(@end)">
        <place><xsl:value-of select="@end"></place>
    </xsl:if>
</xsl:template>


<xsl:variable name="rtfPlaces">
    <xsl:apply-templates select="trip/leg" mode="tour" />
</xsl:variable>

<xsl:variable name="places" select="exslt:node-set($rtfPlaces)" />

<xsl:variable name="uniquePlaces" select="$places/place[1] | $places/place[.!=preceding-sibling::place[1]]" /> 

Решение: действительно обработайте это в два прохода. Получите @start и @end в нужном порядке, написав их отдельно. Затем выберите уникальные значения на втором проходе.

Это не дает мне элемент trip в выводе, но я не думаю, что мне это действительно нужно.

И для этого требуется расширение набора узлов, но это тоже нормально.

Если все это можно сделать за один проход, я не понимаю, как.

1 Ответ

1 голос
/ 06 февраля 2012

Это должно получиться за один проход ...

Ввод XML

<trip>
  <leg start="MA" stop="MA" />
  <leg start="MA" stop="CT" />
  <leg start="NY"           />
  <leg                      />
  <leg start="DE"           />
  <leg            stop="DE" />
  <leg start="NY" stop="PA" />
</trip>

XSLT 1.0

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

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

  <xsl:template match="trip">
    <trip>
      <xsl:apply-templates/>
    </trip>
  </xsl:template>

  <!--This is so we don't get duplicate entries 
    for both attributes when they are the same.-->
  <xsl:template match="@stop[.=parent::*/@start]"/>

  <xsl:template match="@start|@stop">
    <xsl:if test="not(parent::leg/preceding-sibling::leg[1][@start = current() or @end = current()])">
      <place><xsl:value-of select="."/></place>      
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

Вывод XML

<trip>
   <place>MA</place>
   <place>CT</place>
   <place>NY</place>
   <place>DE</place>
   <place>NY</place>
   <place>PA</place>
</trip>

Вы также можете добавить этот шаблон, чтобы быть на 100% уверенным, что @start обрабатывался до @stop:

  <xsl:template match="leg">
    <xsl:apply-templates select="@start"/>
    <xsl:apply-templates select="@stop"/>
  </xsl:template>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...