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

XPath - отбор ближайших потомков

Метки: [без меток]
2011-09-01 15:43:55 [обр] Principal AG(5/11)[досье]
Всем доброго в.с.
Возникла странная непонятка со сравнением узлов в XPath выражении.
Существует XML описывающий некую иерархическую файловую структуру и содержащий типичные теги <directory> и <files> вложенные всяко-разно друг в друга.
Находясь в некоторой точке <directory> необходимо выбрать всех её потомков <files> для которых эта <directory> является ближайшим родителем типа "<directory>" т.е. только тех, которые ни в какую <directory> кроме её самой (исходной) больше не вложены.
Отношения child / parent не проходят т.к в документе существуют и другие (не files /directory ) теги, поэтому только ancestor / descendant.
Пишу казалось бы тривиальное выражение:
descendant::files[ancestor::directory[1] = self::node()]
Но предиката как-будто и не работает т.е. элементы с другими родительскими directory не отсекаются.
Когда маразм дошёл до крайней точки написал даже:
descendant::files[parent::node() = self::node()]
Но и это казалось бы абсурдное выражение ничего не отсекло.
В чём тут может быть дело? Может быть self::node() интерпретируется как-то не так как мне хочется, или оператор "=" сравнивает узлы каким-то особым образом?
Заранее спасибо.
спустя 17 часов [обр] Lynn «Кофеман»(52/571)[досье]
Можно пример XML-я «существуют и другие (не files /directory ) теги, поэтому только ancestor / descendant»?
И может проще исправить структуру XML?
спустя 3 часа 38 минут [обр] Principal AG(5/11)[досье]
сообщение промодерировано

Вот исходный текст XML (самый короткий, который нашёл). Получается он путём сканирования всей иерархии директорий и сложения отдельных файликов.
Вся завязка идёт не между отношениями files /directory (как писал раньше, для простоты), а между pcl:* /directory, хотя в данном случае это скорее всего и не важно.
Т.е. Запрос имеет такой вид:
descendant::pcl:*[ancestor::pcl:*[1] = self::node()]
А маразматичный запрос соответственно:
descendant::pcl:item[parent::node() = self::node()]

<pcl:access xmlns:pcl="http://www.principal.ru/0.7.1" xmlns:xlink="http://www.w3.org/1999/xlink" axis="ancestor">
   <pcl:list xlink:type="none" xlink:title="Главное меню">
      <pcl:item name="home" xlink:type="simple" xlink:href="/index.xml" xlink:title="Главная">
         <files match="/index.*"/>
      </pcl:item>
      <pcl:item name="about" xlink:type="simple" xlink:href="/about.xml" xlink:title="О нас">
         <files match="/about.*"/>
      </pcl:item>
      <pcl:item name="contacts" xlink:type="simple" xlink:href="/contacts.xml" xlink:title="Контакты">
         <files match="/contacts.*"/>
      </pcl:item>
      <files match="/*.*"/>
      <directory match="/simple" name="simple" axis="ancestor">
         <pcl:item name="catalogue" xlink:type="simple" xlink:href="/catalogue/index.xml" xlink:title="Каталог">
            <directory match="/catalog"/>
            <directory match="/cat*" name="catalogue" axis="ancestor">
               <pcl:item name="vendors" xlink:type="simple" xlink:href="./index.xml" xlink:title="Производители">
                  <directory match="/vendors" name="vendors" axis="ancestor">
                     <directory name="makita" axis="self">
                        <pcl:item name="index" xlink:type="simple" xlink:href="/index.xml" xlink:title="Продукты Макита">
                           <files match="/index.*"/>
                        </pcl:item>
                        <pcl:list xlink:type="none" xlink:title="Электроинструмент Макита">
                           <pcl:item name="HR" xlink:type="simple" xlink:href="/index_HR.xml"
                              xlink:title="Перфораторы и отбойные молотки">
                              <files match="/HR.*"/>
                           </pcl:item>
                           <pcl:item name="HP" xlink:type="simple" xlink:href="/index_HP.xml" xlink:title="Дрели и шуруповерты">
                              <files match="/HP.*"/>
                           </pcl:item>
                           <files match="/*.*"/>
                        </pcl:list>
                        <directory match="/*"/>
                     </directory>
                  </directory>
               </pcl:item>
               <pcl:item name="products" xlink:type="simple" xlink:href="./index.xml" xlink:title="Асортимент">
                  <directory match="/products"/>
               </pcl:item>
               <directory match="/*"/>
            </directory>
            <directory match="/ctalogue"/>
            <directory match="/ctalog*"/>
         </pcl:item>
         <directory match="/*"/>
      </directory>
   </pcl:list>
   <directory match="/*"/>
</pcl:access>

Повторюсь, эти запросы ведут себя таким образом, как будто предикат вообще не существует.

А вообще полностью задача такая:

  1. Нахожусь в узле - <files match="/HR.*"/>
  2. Завязываю цикл на запросе - ancestor::pcl:* (выбираю всех предков от корня)
  3. Из него уже вызываю - descendant::pcl:*[ancestor::pcl:*[1] = self::node()]
  4. Жду, что на каждом шаге цикла у меня будут отбираться только непосредственные десценданты текущего узла (т.е. те, для которых ближайший предок pcl:* и есть текущий узел).

А отбираются все потомки без отсечки.

спустя 10 дней [обр] Lynn «Кофеман»(52/571)[досье]

Что-то я плохо уловил, что же именно нужно.
У меня получилось вот так:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:pcl="http://www.principal.ru/0.7.1" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>
  <xsl:template match="/">
    <root>
      <xsl:apply-templates select="//files[@match='/HR.*']"/>
    </root>
  </xsl:template>
  <xsl:template match="files">
    <xsl:for-each select="ancestor::directory[1]">
      <xsl:variable name="cur" select="."/>
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each select="descendant::files[ancestor::directory[1] = $cur]">
          <xsl:copy>
            <xsl:copy-of select="@*"/>
          </xsl:copy>
        </xsl:for-each>
      </xsl:copy>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

с вот таким результатом:

$ xsltproc transform.xsl in.xml 
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:pcl="http://www.principal.ru/0.7.1" xmlns:xlink="http://www.w3.org/1999/xlink">
  <directory name="makita" axis="self">
    <files match="/index.*"/>
    <files match="/HR.*"/>
    <files match="/HP.*"/>
    <files match="/*.*"/>
  </directory>
</root>

Текущий узел directory пришлось положить в переменную, что бы было с чем сравнивать в предикате.

спустя 5 дней [обр] Principal AG(5/11)[досье]
К сожалению обработка ведётся не на XSLT. Использование переменных в теле XPath выражения невозможно.
Сформулирую вопрос так - Можно ли в теле XPath выражения каким либо образом сослаться на узел (элемент) к которому собственно и применяется это выражение (т.е. с которого начинается поиск)?
Естественно средствами самого XPath 1.0.
спустя 13 часов [обр] Lynn «Кофеман»(52/571)[досье]
Есть функция current(), собственно в моём примере можно заменить переменную $cur на эту функцию.
Powered by POEM™ Engine Copyright © 2002-2005