Создание вложенного XML с использованием метода muenchian в XLST - PullRequest
4 голосов
/ 20 июня 2011

Я пытаюсь создать вложенный XML-документ из простого XML-документа, как показано ниже.После поиска здесь и других ресурсов, доступных в сети, кажется, что метод muenchain мог бы быть решением, однако я изо всех сил пытаюсь применить его в моей ситуации.

XML, который мне нужно перевести, имеет форму:

<i>
  <item id="1" name="one" sub_id="10" sub_name="s1" detail_id="t1" detail_name="aaaa"/>
  <item id="1" name="one" sub_id="10" sub_name="s1" detail_id="t2" detail_name="bbb"/>
  <item id="1" name="one" sub_id="20" sub_name="s2" detail_id="t1" detail_name="ccc"/>
  <item id="1" name="one" sub_id="20" sub_name="s2" detail_id="t2" detail_name="ddd"/>
  <item id="2" name="two" sub_id="10" sub_name="s1" detail_id="t1" detail_name="eee"/>
  <item id="2" name="two" sub_id="10" sub_name="s1" detail_id="t2" detail_name="fff"/>
  <item id="2" name="two" sub_id="20" sub_name="s2" detail_id="t1" detail_name="ggg"/>
  <item id="2" name="two" sub_id="20" sub_name="s2" detail_id="t2" detail_name="hhh"/>
  <item id="3" name="three" />
  <item id="4" name="four" sub_id="10" sub_name="s1" detail_id="t1" detail_name="mmm"/>
  <item id="4" name="four" sub_id="10" sub_name="s1" detail_id="t2" detail_name="nnn"/>
  <item id="4" name="four" sub_id="20" sub_name="s2" detail_id="t1" detail_name="ooo"/>
  <item id="4" name="four" sub_id="20" sub_name="s2" detail_id="t2" detail_name="ppp"/>
</i>

Я хотел бы преобразовать это в XML в следующей форме:

  <i>
    <item id="1" name="one" sub_items="true">
      <sub_item sub_id="10" sub_name="s1">
        <detail detail_id="t1" detail_name="aaaa"/>
        <detail detail_id="t2" detail_name="bbb"/>
      </sub_item>
      <sub_item sub_id="20" sub_name="s2">
        <detail detail_id="t1" detail_name="ccc"/>
        <detail detail_id="t2" detail_name="ddd"/>
      </sub_item>
    </item>
    <item id="2" name="two" sub_items="true">
      <sub_item sub_id="10" sub_name="s1">
        <detail detail_id="t1" detail_name="eee"/>
        <detail detail_id="t2" detail_name="fff"/>
      </sub_item>
      <sub_item sub_id="20" sub_name="s2">
        <detail detail_id="t1" detail_name="ggg"/>
        <detail detail_id="t2" detail_name="hhh"/>
      </sub_item>
    </item>
    <item id="3" name="three" sub_items="false"/>
    <item id="4" name="four" sub_items="true">
      <sub_item sub_id="10" sub_name="s1">
        <detail detail_id="t1" detail_name="mmm"/>
        <detail detail_id="t2" detail_name="nnn"/>
      </sub_item>
      <sub_item sub_id="20" sub_name="s2">
        <detail detail_id="t1" detail_name="ooo"/>
        <detail detail_id="t2" detail_name="ppp"/>
      </sub_item>
    </item>
  </i>

Из моего исследованияУ меня есть следующий XLST для выполнения преобразования.Я использую метод key в атрибуте item item.Это не группирует данные правильно, повторяя все для данного идентификатора элемента на каждом уровне - что имеет смысл, учитывая ключ.Поэтому моя проблема в том, как мне выбрать узлы, необходимые для вывода каждого уровня гнезда, и мне нужно использовать другой ключевой оператор?

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="indexes" match="i/item" use="@id"/>
  <xsl:template match="i">
    <i>
    <xsl:for-each select="item[count(. | key('indexes',@id)[1]) = 1]"  >
      <xsl:sort select="@id"/>
      <item>
        <xsl:attribute name="id">
          <xsl:value-of select="@id"/>
        </xsl:attribute>
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <xsl:attribute name="hasRows">
          <xsl:value-of select="@id"/>
        </xsl:attribute>
        <xsl:for-each select="key('indexes',@id)">
          <subitem>
            <xsl:attribute name ="sub_id">
              <xsl:value-of select="@sub_id"/>
            </xsl:attribute>
            <xsl:attribute name ="sub_name">
              <xsl:value-of select="@sub_name"/>
            </xsl:attribute>
            <xsl:for-each select="key('indexes',@id)">
              <segment>
                <xsl:attribute name ="detail_id">
                  <xsl:value-of select="@detail_id"/>
                </xsl:attribute>
                <xsl:attribute name ="detail_name">
                  <xsl:value-of select="@detail_name"/>
                </xsl:attribute>
              </segment>
            </xsl:for-each>
          </subitem>
        </xsl:for-each>
      </item>
    </xsl:for-each>
    </i>
  </xsl:template>
</xsl:stylesheet>

Также возможно заполнить атрибут * sub_items * true , когда существуют подэлементы / детали для элемента, и false , когда их нет?

Наконец, для улучшения понимания / навыков XSLT кто-нибудь может порекомендовать хорошие учебные ресурсы?

Ответы [ 2 ]

2 голосов
/ 20 июня 2011

Метод Мюнхена сложен для вложенной группировки. Первый уровень группировки прост в управлении, но для остальных вам нужно индексировать элементы с помощью составных ключей, составленных из предыдущих идентификаторов.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" />
    <xsl:key name="items" match="item" use="@id" />
    <xsl:key name="sub-items" match="item" use="concat(@id, '|', @sub_id)" />
    <xsl:template match="i">
      <i>
        <xsl:for-each select="item[generate-id() = generate-id(key('items', @id)[1])]">
          <xsl:copy>
           <xsl:copy-of select="@id|@name" />
           <xsl:choose>
             <xsl:when test="count(key('items', @id)) &gt; 1">
           <xsl:attribute name="sub_items">true</xsl:attribute>
           <xsl:for-each select="key('items', @id)[generate-id() = generate-id(key('sub-items', concat(@id, '|', @sub_id))[1])]">
             <sub_item>
            <xsl:copy-of select="@sub_id|@sub_name" />
            <xsl:for-each select="key('sub-items', concat(@id, '|', @sub_id))">
              <detail>
                <xsl:copy-of select="@detail_id|@detail_name" />
              </detail>
             </xsl:for-each>
             </sub_item>
           </xsl:for-each>
         </xsl:when>
          <xsl:otherwise>
            <xsl:attribute name="sub_items">false</xsl:attribute>
          </xsl:otherwise>
        </xsl:choose> 
          </xsl:copy>   
        </xsl:for-each> 
      </i>
    </xsl:template>
</xsl:stylesheet>
1 голос
/ 21 июня 2011

Обратите внимание на это преобразование XSLT 1.0 с использованием:

  • AVT (шаблоны значений атрибутов) для упрощения определения атрибутов)
  • один главный ключ, используемый для группировки элемента первого уровня
  • Одна вторая составная клавиша для группировки подуровней
  • расширенное использование xsl:apply-templates с режимами, по сравнению с xsl:for-each

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:key name="kSubs" match="item" use="concat(@id,'|',@sub_id)"/> 
    <xsl:key name="kItems" match="item" use="@id"/> 
    
    <xsl:template match="i">
        <i>
            <xsl:apply-templates select="item[
                generate-id()
                    = generate-id(key('kItems',@id)[1])]"/>
        </i>
    </xsl:template>
    
    <xsl:template match="item">
        <item id="{@id}" name="{@name}" sub_items="{boolean(@sub_id)}">
            <xsl:apply-templates select=".|following-sibling::item[
                (generate-id()
                        = generate-id(key('kSubs',concat(@id,'|',@sub_id))[1]))
                and
                (./@id 
                        = current()/@id)
                ]" mode="sub_id"/>
        </item>
    </xsl:template>
    
    <xsl:template match="item[@sub_id]" mode="sub_id">
        <sub_item sub_id="{@sub_id}" sub_name="{@sub_name}">
            <xsl:apply-templates select="key('kSubs',concat(@id,'|',@sub_id))" 
             mode="detail"/>
        </sub_item>
    </xsl:template>
    
    <xsl:template match="item" mode="detail">
        <detail detail_id="{@detail_id}" detail_name="{@detail_name}"/>
    </xsl:template>
    
    </xsl:stylesheet>
    

Применительно к входу, указанному в вашем вопросе, выдает:

<i>
   <item id="1" name="one" sub_items="true">
      <sub_item sub_id="10" sub_name="s1">
         <detail detail_id="t1" detail_name="aaaa"/>
         <detail detail_id="t2" detail_name="bbb"/>
      </sub_item>
      <sub_item sub_id="20" sub_name="s2">
         <detail detail_id="t1" detail_name="ccc"/>
         <detail detail_id="t2" detail_name="ddd"/>
      </sub_item>
   </item>
   <item id="2" name="two" sub_items="true">
      <sub_item sub_id="10" sub_name="s1">
         <detail detail_id="t1" detail_name="eee"/>
         <detail detail_id="t2" detail_name="fff"/>
      </sub_item>
      <sub_item sub_id="20" sub_name="s2">
         <detail detail_id="t1" detail_name="ggg"/>
         <detail detail_id="t2" detail_name="hhh"/>
      </sub_item>
   </item>
   <item id="3" name="three" sub_items="false"/>
   <item id="4" name="four" sub_items="true">
      <sub_item sub_id="10" sub_name="s1">
         <detail detail_id="t1" detail_name="mmm"/>
         <detail detail_id="t2" detail_name="nnn"/>
      </sub_item>
      <sub_item sub_id="20" sub_name="s2">
         <detail detail_id="t1" detail_name="ooo"/>
         <detail detail_id="t2" detail_name="ppp"/>
      </sub_item>
   </item>
</i>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...