Xpoint
   [напомнить пароль]

Предшествующая и последующие узлы

Метки: [без меток]
2011-03-22 10:45:48 [обр] walek[досье]

Привет.

Допустим у меня есть такой xml:

<channel>
...
<item>
  <ID>1605540</ID>
  <category>Политика</category>
  <title>Заголовок 1</title>
</item>
<item>
  <ID>1605547</ID>
  <category>Политика</category>
  <title>Заголовок 2</title>
</item>
<item>
  <ID>1605544</ID>
  <category>Общество</category>
  <title>Заголовок 3</title>
</item>
<item>
  <ID>1605541</ID>
  <category>Общество</category>
  <title>Заголовок 4</title>
</item>
<item>
  <ID>1605551</ID>
  <category>Культура</category>
  <title>Заголовок 5</title>
</item>
<item>
  <ID>1605570</ID>
  <category>Культура</category>
  <title>Заголовок 6</title>
</item>
...
</channel>

Мне нужно получать в текущем узле item[ID=$ArtID], где $ArtID=1605544, берется из <xsl:param name="ArtID" select="ID" /> получать название предыдущей и последующей категорий. Привёл кусочек xml, потому что item много, но логика думаю понятна. Категорий 16 и у каждой несколько статей.

Делаю так:

<xsl:key name="key-category" match="item" use="category" />
<xsl:template match="channel">
  <xsl:apply-templates select="item[generate-id(.)=generate-id(key('key-category', category))][ID=$ArtID]" />
</xsl:template>

<xsl:template match="item">
  <xsl:value-of select="preceding-sibling::item[not(category=current()/category)]/category" />
  <xsl:value-of select="following-sibling::item[not(category=current()/category)]/category" />
</xsl:template>

Последующая категория вытаскивается, а предшествующая нет. Что не так?
Спасибо.

спустя 1 день [обр] Jared(0/26)[досье]
Какой процессор вы используете?
У меня LibXML/LibXSLT отработали именно так, как Вам нужно.
спустя 2 часа 20 минут [обр] walek[досье]
Jared, MSXML 4.0
спустя 1 час 57 минут [обр] walek[досье]
Jared,
Думаю я не доконца объяснил, <xsl:value-of select="preceding-sibling::item[not(category=current()/category)]/category" />, в том кусочке, который привёл, действительно, работает так как нужно, но это на первый взгляд.
На самом деле он выбирает самый первый узел, а не предшествующий.
спустя 2 часа 16 минут [обр] Jared(0/26)[досье]

walek[досье] То есть, вам нужен строго предыдущий узел у которого категория не равна категории текущего?

<xsl:value-of select="preceding-sibling::item[not(category=current()/category)][1]/category" />

То есть, насколько я понимаю, preceding-sibling создает нод-сет, первым из которого без указания индекса идет тот узел, что раньше объявлен в документе. Индексация, правда, все равно идет в обратном порядке.

спустя 1 час 53 минуты [обр] walek[досье]

Jared, да, нужны строго статьи предыдущей категории.
Правда в этом наборе нужно получить строго первую статью.

Ваш пример выбирает последню из нод-сета, а как первую выбрать? Не подскажите?

спустя 59 минут [обр] Jared(0/26)[досье]
Правда в этом наборе нужно получить строго первую статью.

Что-то я запутался...

<item>
  <ID>1515540</ID>
  <category>Спорт</category>
  <title>Спортивный Заголовок 1</title>
</item>
<item>
  <ID>1605540</ID>
  <category>Политика</category>
  <title>Политический Заголовок 1</title>
</item>
<item>
  <ID>1605547</ID>
  <category>Политика</category>
  <title>Политический Заголовок 2</title>
</item>
<item>
  <ID>1605544</ID>
  <category>Общество</category>
  <title>Заголовок 3</title>
</item>

Здесь например вам для ID 1605544 (Общество) нужно получить 1605540 (Политический Заголовок 1) - первая статья строго предыдущей категории?

спустя 1 час 9 минут [обр] walek[досье]
Jared, всё верно, статей с одинаковыми категориями может быть >1, поэтому нужна предыдущая статья строго первая в категории.
спустя 9 часов [обр] Jared(0/26)[досье]

walek[досье] У меня получилась такая конструкция:

<xsl:template match="item">
    <!-- Получаем имя строго предыдущей категории. Создаем "переменную", чтобы не воротить страшный XPath позже -->
    <xsl:variable name='prevcat'><xsl:value-of select="preceding-sibling::item[not(category=current()/category)][1]/category"/></xsl:variable>
    <!-- Нода - первый в документе итем в этой строго предыдущей категории -->
    <xsl:value-of select="preceding-sibling::item[category=$prevcat][last()]/category" />
    <xsl:value-of select="following-sibling::item[not(category=current()/category)]/category" />
</xsl:template>

Хотя, как по мне, проще и правильнее формировать изначально более подходящий для этих данных XML:

<category name='Спорт'>
   <item>
      <ID>1515540</ID>
      <title>Спортивный Заголовок 1</title>
   </item>
</category>
<category name='Политика'>
   <item>
      <ID>1605540</ID>
      <title>Политический Заголовок 1</title>
   </item>
   <item>
      <ID>1605547</ID>
      <title>Политический Заголовок 2</title>
   </item>
</category>
<category name='Общество'>
   <item>
   <ID>1605544</ID>
   <title>Заголовок 3</title>
   </item>
</category>
спустя 3 часа 20 минут [обр] walek[досье]

Jared, спасибо вам! Это то, что нужно.

К сожалению влиять на структуру XML нет возможности.

Powered by POEM™ Engine Copyright © 2002-2005