2012-02-04 14 views
7

Korzystając z XSLT/XPATH 1.0, chcę utworzyć kod HTML, w którym atrybut class elementu span wskazuje głębokość w oryginalnej hierarchii XML.Głębokość wyprowadzania bieżącego węzła w hierarchii

Na przykład, w tym XML fragment:

<text> 
    <div type="Book" n="3"> 
     <div type="Chapter" n="6"> 
      <div type="Verse" n="12"> 
      </div> 
     </div> 
    </div> 
</text> 

chcę to HTML:

<span class="level1">Book 3</span> 
<span class="level2">Chapter 6</span> 
<span class="level3">Verse 12</span> 

Jak głęboko te div elementów może pójść nie jest znana a priori. div s może być Książka -> Rozdział. Mogą to być: Volume -> Book -> Chapter -> Paragraph -> Line.

Nie mogę polegać na wartościach @type. Niektóre lub wszystkie mogą być wartościami NULL.

Odpowiedz

16

To ma bardzo prosty i krótki rozwiązanie - nie rekursji, żadnych parametrów nie xsl:element, nie xsl:attribute:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="div"> 
    <span class="level{count(ancestor::*)}"> 
    <xsl:value-of select="concat(@type, ' ', @n)"/> 
    </span> 
    <xsl:apply-templates/> 
</xsl:template> 
</xsl:stylesheet> 

kiedy ta transformacja jest stosowana na dołączonej dokumentu XML:

<text> 
    <div type="Book" n="3"> 
     <div type="Chapter" n="6"> 
      <div type="Verse" n="12"></div></div></div> 
</text> 

poszukiwany, poprawny wynik jest produkowany:

<span class="level1">Book 3</span> 
<span class="level2">Chapter 6</span> 
<span class="level3">Verse 12</span> 

Wyjaśnienie: Właściwe stosowanie szablonów, AVT i funkcji count().

0

Jak zwykle z XSL, użyj rekursji.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" indent="yes"/> 

    <xsl:template match="/text"> 
    <html> 
     <xsl:apply-templates> 
     <xsl:with-param name="level" select="1"/> 
     </xsl:apply-templates> 
    </html> 
    </xsl:template> 


    <xsl:template match="div"> 
    <xsl:param name="level"/> 

    <span class="{concat('level',$level)}"><xsl:value-of select="@type"/> <xsl:value-of select="@n"/></span> 

    <xsl:apply-templates> 
     <xsl:with-param name="level" select="$level+1"/> 
    </xsl:apply-templates> 
    </xsl:template> 


</xsl:stylesheet> 
5

Albo bez użycia rekurencji - ale odpowiedź Dimitre jest lepszy niż mój jeden

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" indent="yes"/> 

<xsl:template match="/text"> 
    <html> 
     <body> 
      <xsl:apply-templates/> 
     </body> 
    </html> 
</xsl:template> 

<xsl:template match="//div"> 
    <xsl:variable name="depth" select="count(ancestor::*)"/> 
    <xsl:if test="$depth > 0"> 
     <xsl:element name="span"> 
      <xsl:attribute name="class"> 
       <xsl:value-of select="concat('level',$depth)"/> 
      </xsl:attribute> 
      <xsl:value-of select="concat(@type, ' ' , @n)"/> 
     </xsl:element> 
    </xsl:if> 
    <xsl:apply-templates/> 
</xsl:template> 

</xsl:stylesheet> 
Powiązane problemy