Шаблон xsl, который выделяет текст между двумя пустыми узлами - PullRequest
0 голосов
/ 06 июня 2011

У меня есть XML-файл в следующем формате.

<root>
...

<start/>
 some text <b> bold </b>
<end/>
...

<start/>
 some other text <i>italic </i>
<end/>
...
</root>

Пожалуйста, предложите мне шаблон xsl, который выделяет весь текст между тегами <start/> и <end/>. Обратите внимание: <start/> и <end/> - пустые узлы. Большое спасибо.

1 Ответ

3 голосов
/ 06 июня 2011

Я интерпретирую ваш "весь текст", чтобы он включал не только сами текстовые узлы, но и разметку, например <b>. Я также предполагаю, что вы не хотите выбирать каждый узел-потомок между <start/> и <end/>, а только самые верхние. Кроме того, я предполагаю, что все теги <start/> и <end/> являются братьями и сестрами (не может быть на любом уровне).

Используйте следующий шаблон, чтобы выделить (и скопировать) весь текст между тегами <start/> и <end/>.

<xsl:template match="/">
   <xsl:copy-of select="(//start)[1]/following-sibling::node()[not(self::end) and 
         name((preceding-sibling::start | preceding-sibling::end)[last()]) = 'start']"/>
</xsl:template>

Обновление: Учитывая, что ваш начало / конец может быть на любом уровне, вы можете удалить -sibling из осей выше:

  select="(//start)[1]/following::node()[not(self::end) and 
        name((preceding::start | preceding::end)[last()]) = 'start']"

Однако это выбирает все узлы, а не только узлы верхнего уровня. (И поэтому, если вы глубоко скопируете выбранные узлы, вы получите дубликаты.) Это потому, что неясно определено, какое поведение должно произойти, если у вас было что-то вроде этого:

<start/>
<chapter>foo<end/></chapter>

Должен ли <chapter> быть выбран или нет? Однако, если вы можете наложить дополнительные ограничения на то, где начало / конец могут падать по отношению друг к другу, мы можем добиться большего. Например. каждый <end/> родной брат предыдущего <start/>? Если это так, вы могли бы сделать

<xsl:key name="text-by-last-milestone" match="* | text()"
      use="generate-id((preceding-sibling::start | preceding-sibling::end)[last()])" />
<xsl:template match="/">
   <xsl:for-each select="//start">
      <xsl:copy-of select="key('text-by-last-milestone', generate-id())"/>
   </xsl:for-each>
</xsl:template>

Если нет, то вам будет полезно показать более расширенный образец вашего ввода.

К вашему сведению, эти теги называются «вехой» разметки, поэтому вы можете найти больше информации об их обработке, выполнив поиск по этому термину. В зависимости от ограничений входного XML-кода они также рассматриваются как «одновременная разметка».

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