2010-05-14 4 views
15

Im новое для XSLT, и у меня возникают некоторые проблемы с форматированием XML-документа с рекурсивными узлами.Шаблоны XSLT и рекурсия

Мой XML код:

Надеюсь, мой XML показывает:

  • Все <item> вложены с <items>
  • Элемент может иметь либо только атрибуты, или суб узлы
  • Уровень, до которого <item> Узлы вложенные могут быть бесконечно глубокими
<?xml version="1.0" encoding="utf-8" ?> 
- <items> 
    <item groupID="1" name="Home" url="//" /> 
- <item groupID="2" name="Guides" url="/Guides/"> 
- <items> 
- <item groupID="26" name="Online-Poker-Guide" url="/Guides/Online-Poker-Guide/"> 
- <items> 
- <item> 
    <id>107</id> 
- <title> 
- <![CDATA[ Poker Betting - Online Poker Betting Structures 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/online-poker-betting-structures 
    ]]> 
    </url> 
    </item> 
- <item> 
    <id>114</id> 
- <title> 
- <![CDATA[ Beginners&#39; Poker - Poker Hand Ranking 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/online-poker-hand-ranking 
    ]]> 
    </url> 
    </item> 
- <item> 
    <id>115</id> 
- <title> 
- <![CDATA[ Poker Terms - 4th Street and 5th Street 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/online-poker-poker-terms 
    ]]> 
    </url> 
    </item> 
- <item> 
    <id>116</id> 
- <title> 
- <![CDATA[ Popular Poker - The Popularity of Texas Hold&#39;em 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/online-poker-popularity-texas-holdem 
    ]]> 
    </url> 
    </item> 
- <item> 
    <id>364</id> 
- <title> 
- <![CDATA[ The Impact of Traditional Poker on Online Poker (and vice versa) 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/online-poker-tradional-vs-online 
    ]]> 
    </url> 
    </item> 
- <item> 
    <id>365</id> 
- <title> 
- <![CDATA[ The Ultimate, Absolute Online Poker Scandal 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/online-poker-scandal 
    ]]> 
    </url> 
    </item> 
    </items> 
- <items> 
- <item groupID="27" name="Beginners-Poker" url="/Guides/Online-Poker-Guide/Beginners-Poker/"> 
- <items> 
+ <item> 
    <id>101</id> 
- <title> 
- <![CDATA[ Poker Betting - All-in On the Flop 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/poker-betting-all-in-on-the-flop 
    ]]> 
    </url> 
    </item> 
+ <item> 
    <id>102</id> 
- <title> 
- <![CDATA[ Beginners&#39; Poker - Choosing an Online Poker Room 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/beginners-poker-choosing-a-room 
    ]]> 
    </url> 
    </item> 
+ <item> 
    <id>105</id> 
- <title> 
- <![CDATA[ Beginners&#39; Poker - Choosing What Type of Poker to Play 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/beginners-poker-choosing-type-to-play 
    ]]> 
    </url> 
    </item> 
+ <item> 
    <id>106</id> 
- <title> 
- <![CDATA[ Online Poker - Different Types of Online Poker 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/online-poker 
    ]]> 
    </url> 
    </item> 
+ <item> 
    <id>109</id> 
- <title> 
- <![CDATA[ Online Poker - Opening an Account at an Online Poker Site 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/online-poker-opening-an-account 
    ]]> 
    </url> 
    </item> 
+ <item> 
    <id>111</id> 
- <title> 
- <![CDATA[ Beginners&#39; Poker - Poker Glossary 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/beginners-poker-glossary 
    ]]> 
    </url> 
    </item> 
+ <item> 
    <id>117</id> 
- <title> 
- <![CDATA[ Poker Betting - What is a Blind? 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/poker-betting-what-is-a-blind 
    ]]> 
    </url> 
    </item> 
- <item> 
    <id>118</id> 
- <title> 
- <![CDATA[ Poker Betting - What is an Ante? 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/poker-betting-what-is-an-ante 
    ]]> 
    </url> 
    </item> 
+ <item> 
    <id>119</id> 
- <title> 
- <![CDATA[ Beginners Poker - What is Bluffing? 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/online-poker-what-is-bluffing 
    ]]> 
    </url> 
    </item> 
- <item> 
    <id>120</id> 
- <title> 
- <![CDATA[ Poker Games - What is Community Card Poker? 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/online-poker-what-is-community-card-poker 
    ]]> 
    </url> 
    </item> 
- <item> 
    <id>121</id> 
- <title> 
- <![CDATA[ Online Poker - What is Online Poker? 
    ]]> 
    </title> 
- <url> 
- <![CDATA[ /Guides/Online-Poker-Guide/Beginners-Poker/online-poker-what-is-online-poker 
    ]]> 
    </url> 
    </item> 
    </items> 
    </item> 
    </items> 
    </item> 
    </items> 
    </item> 
    </items> 

код XSL:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="html" indent="yes"/> 

    <xsl:template name="loop"> 
     <xsl:for-each select="items/item"> 
      <ul> 
      <li><xsl:value-of select="@name" /></li> 
      <xsl:if test="@name and child::node()"> 
       <ul> 
        <xsl:for-each select="items/item"> 
         <li><xsl:value-of select="@name" />test</li> 
        </xsl:for-each> 
       </ul> 
       <xsl:call-template name="loop" /> 
      </xsl:if> 
      <xsl:if test="child::node() and not(@name)"> 
       <xsl:for-each select="/items"> 
        <li><xsl:value-of select="id" /></li> 
       </xsl:for-each> 
      </xsl:if> 
      </ul> 
     </xsl:for-each> 
     <xsl:for-each select="item/items/item"> 
      <li>hi</li> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="/" name="test"> 
      <xsl:call-template name="loop" /> 
    </xsl:template> 

</xsl:stylesheet> 

Im пытается написать XSL, так что каждый узел <items> будет оказывать <ul> и каждый <items> узел воздаст <li>.

XSL должен быть рекурсивным, потому что я не могу сказать, насколько глубоко вложены вложенные узлы.

Может ли кто-нибудь помочь?

С уважением, Al

+3

Вы можете заменить образец XML с немного меньшим тот, который просто XML (я предполагаю, что «+» и «-» символы были добавлены зрителем) и добавить образец желаемых результатов? Это поможет нам более четко понять, что вам нужно, и позволить нам более легко попробовать что-то с вашим xml. –

ответ

20

Это очень просто. Процессор XSLT выполняет всю рекурсию и цикл для вас, все, что вам нужно сделать, это указать шаблоны для узлов, которые вы хотите обработать.

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <!-- <items> with <item> children becomes <ul> --> 
    <xsl:template match="items[item]"> 
    <ul> 
     <xsl:apply-templates select="item" /> 
    </ul> 
    </xsl:template> 

    <!-- <items> without <item> children is not handled --> 
    <xsl:template match="items[not(item)]" /> 

    <!-- <item> with @name becomes <li> --> 
    <xsl:template match="item[@name]"> 
    <li> 
     <xsl:value-of select ="@name" /> 
     <xsl:apply-templates select="items" /> 
    </li> 
    </xsl:template> 

    <!-- <item> without @name becomes <li>, too --> 
    <xsl:template match="item[not(@name)]"> 
    <li> 
     <xsl:value-of select ="id" /> 
     <xsl:apply-templates select="items" /> 
    </li> 
    </xsl:template> 
</xsl:stylesheet> 

The <xsl:apply-templates> всегда является рекурсивным/итерационный шаг в XSLT. Он принимает любые узлы, которые соответствуют его выражению select и находит шаблоны для них.

Ваша задача - создать подходящее выражение select, предоставить шаблон для каждого узла, который вы хотите обработать, и в противном случае уйти с пути. ;-) Сопротивляйтесь стремлению втиснуть все в один большой шаблон или использовать <xsl:for-each> только потому, что он чувствует себя удобно - это не так.Отдельные шаблоны создают более многоразовый и поддерживаемый, менее глубоко вложенный код, а XSLT-процессоры оптимизированы для обработки шаблонов, поэтому это может быть даже более эффективный подход.

0

Я думаю, вы можете просто написать XSL-T в соответствии с <item>. Единственный способ рекурсии имел бы значение, если бы вы хотели сохранить родительские/дочерние отношения. Согласование на <item> будет достаточным, если ваше требование состоит в том, чтобы сопоставить каждый из них с пулей в неупорядоченном списке.

0

Возможно, что-то подобное вам больше понравится?

<?xml version="1.0" encoding="iso-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" indent="yes"/> 

    <xsl:template match="items" mode="loop"> 
    <ul> 
     <xsl:for-each select="item"> 
     <li> 
      <xsl:value-of select ="@name" /> 
      <xsl:value-of select="id" /> 
      <xsl:for-each select="items"> 
      <xsl:apply-templates select="." mode="loop" /> 
      </xsl:for-each> 
     </li> 
     </xsl:for-each> 
    </ul> 
    </xsl:template> 

    <xsl:template match="/" name="test"> 
    <xsl:apply-templates select="/items" mode="loop" /> 
    </xsl:template> 
</xsl:stylesheet> 
3

Вы должны быть в состоянии сделать это, не написав петлю, если я правильно понимаю ваши потребности.

Это, как правило, лучше использовать более декларативный стиль, в данном случае писать шаблон, совпадающий с <items> тег и преобразующий его в <ul> и другой соответствующий <item> преобразования его в <li>. А звонок <xsl:apply-templates/> внутри обоих шаблонов обеспечит рекурсию.

1

Следующая таблица стилей выполняет указанное форматирование. Обратите внимание на использование xsl:apply-templates для восстановления дерева XML. См. 5.4 Applying Template Rules для получения дополнительной информации.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="/"> 
     <xsl:apply-templates select="items"/> 
    </xsl:template> 

    <xsl:template match="items"> 
     <ul> 
      <xsl:apply-templates select="item" /> 
     </ul> 
    </xsl:template> 

    <xsl:template match="item"> 
     <li> 
      <xsl:choose> 
       <xsl:when test="@name"> 
        <xsl:value-of select="@name"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="id"/> 
       </xsl:otherwise> 
      </xsl:choose> 
      <xsl:apply-templates select="items" /> 
     </li> 
    </xsl:template> 
</xsl:stylesheet> 
Смежные вопросы