На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: ANDLL
  
> Как найти все узлы между двумя узлами с помощью XSLT?
    Здравствуйте!

    Прошу помощи в решении следующей задачи: у меня есть XML документ, упрощенно для лучшего понимания задачи такой:
    ExpandedWrap disabled
      <?xml version="1.0" encoding="utf-8"?>
      <pricelist>
        <category>Категория 1</category>
        <vendor>Производитель 1.1.</vendor>
        <product>Продукт 1.1.1</product>
        <product>Продукт 1.1.2</product>
        <product>Продукт 1.1.3</product>
        <category>Категория 2</category>
        <product>Продукт 2.1</product>
        <vendor>Производитель 2.1</vendor>
        <product>Продукт 2.1.1</product>
        <product>Продукт 2.1.2</product>
      </pricelist>

    Нужно его преобразовать в древовидный вид, а именно такой:
    ExpandedWrap disabled
      <?xml version="1.0" encoding="utf-8"?>
      <pricelist>
        <category name="Категория 1">
          <vendor name="Производитель 1.1.">
            <product>Продукт 1.1.1</product>
            <product>Продукт 1.1.2</product>
            <product>Продукт 1.1.3</product>
          </vendor>
        </category>
        <category name="Категория 2">
          <vendor name="Unknown">
            <product>Продукт 2.x</product>
          </vendor>
          <vendor name="Производитель 2.1">
            <product>Продукт 2.1.1</product>
            <product>Продукт 2.1.2</product>
          </vendor>
        </category>
      </pricelist>

    Некоторые пояснения:
    - продукты для которых не указан производитель попадают в специальный производитель с именем Unknown, такой Unknown производитель может быть только один в каждой категории.
    - цифры у продуктов и производителей я добавил только для примера.
    - вообще в прайсе все имена категорий уникальны.
    - имена продуктов и производителей уникальны в пределах категории, но могут повторяться в пределах прайса.

    Я только начал изучать XLST, написал пока такой .xsl файл (могут быть ошибки, т.к. я его переделал для этого упрощенного примера:
    ExpandedWrap disabled
      <?xml version='1.0' encoding="utf-8"?>
      <xsl:stylesheet version="1.0" xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
       
          <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
          <xsl:strip-space elements="*"/>
       
          <xsl:template match="table">
            <pricelist>
            <xsl:apply-templates select="//category"/>
            </pricelist>
          </xsl:template>
       
          <xsl:template match="category">
            <xsl:variable name="category_name">
              <xsl:value-of select="child::text()"/>
            </xsl:variable>
            <category name="{$category_name}">
              <xsl:variable name="next_category"
                           select="(self::node()/following-sibling::category)[1]" />
              <xsl:variable name="current_category" select="self::node()"/>
      <!--
      Тут непонятно что писать...
       
      Я нашел фрагмент со следующей страницы: http://www.biglist.com/lists/xsl-list/archives/200201/msg00659.html
       <xsl:copy-of select="following-sibling::*
                              [generate-id(following-sibling::comma[1]) =
                               generate-id($next-comma)]" />
      Но как его использовать здесь непонятно...
      -->  
       
            </category>
          </xsl:template>
      </xsl:stylesheet>

    Пояснения и вопрос еще я добавил в комментариях XML.

    Прошу помощи именно по XML части. Как можно получить на выходе документ в нужном виде из исходного?
      ExpandedWrap disabled
        <?xml version="1.0" encoding="UTF-8"?>
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
         
            <xsl:template match="/">
                <pricelist>
                    <xsl:apply-templates select="pricelist/category"/>
                </pricelist>
            </xsl:template>
         
            <xsl:template match="category">
                <xsl:apply-templates select="pricelist/category"/>
                <category name="{./text()}">
                    <xsl:apply-templates select="current()[following-sibling::*[1][self::product]]" mode="unknown"/>
         
                    <xsl:apply-templates select="." mode="vendors"/>
                </category>
            </xsl:template>
         
            <xsl:template match="*"/>
         
        <!--//////////////////////////////////////////////////////////////////////////////-->
         
            <xsl:template match="category" mode="unknown">
                <vendor name="Unknown">
                    <xsl:apply-templates select="following-sibling::*[1][self::product]" mode="products"/>
                </vendor>
            </xsl:template>
         
            <xsl:template match="*" mode="unknown"/>
         
        <!--//////////////////////////////////////////////////////////////////////////////-->
         
            <xsl:template match="product" mode="products">
                <xsl:copy-of select="."/>
         
                <xsl:apply-templates select="following-sibling::*[1][self::product]" mode="products"/>
            </xsl:template>
         
            <xsl:template match="*" mode="products"/>
         
        <!--//////////////////////////////////////////////////////////////////////////////-->
         
            <xsl:template match="vendor" mode="vendor">
                <vendor name="{./text()}">
                    <xsl:apply-templates select="following-sibling::*[1][self::product]" mode="products"/>
                </vendor>
            </xsl:template>
         
            <xsl:template match="*" mode="vendor"/>
         
        <!--//////////////////////////////////////////////////////////////////////////////-->
         
            <xsl:template match="category | vendor" mode="vendors">
                <xsl:apply-templates select="." mode="vendor"/>
         
                <xsl:variable name="first_vendor" select="following-sibling::vendor[1]"/>
                <xsl:variable name="next_category" select="following-sibling::category[1]"/>
         
                <xsl:apply-templates select="$first_vendor[not(. = $next_category/following-sibling::*)]" mode="vendors"/>
            </xsl:template>
         
            <xsl:template match="*" mode="vendors"/>
         
        </xsl:stylesheet>
        Запустив я вижу что работает! ss, Спасибо огромное, Вы Мастер!!!
        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script execution time: 0,0222 ]   [ 15 queries used ]   [ Generated: 14.05.24, 23:11 GMT ]