XSLT to align XML hierarchy to HTML table

I got some hierarchical XML:

<node text="a" value="1">
  <node text="gga" value="5">  
    <node text="dh" value="9">
      <node text="tyfg" value="4">  
      </node>  
    </node>  
  </node>  
  <node text="dfhgf" value="7">  
    <node text="fdsg" value="2">  
    </node>  
  </node>  
</node>

The names of the elements are the same up to the end ("node"), and the depth of the hierarchy is not known in advance - in the above example, the deepest sheet has four down, but can be any depth.

What I need to do is take this XML and smooth it into an HTML table. The number of columns in the table should be equal to the depth of the deepest element plus the column for the value attribute for each element. The "value" should appear in the rightmost column of the table, so the output rows cannot have dangling edges. For each node there should be a line, regardless of its level in. The above example should be converted to:

<table>
  <tr>
    <td>a</td>
    <td></td>
    <td></td>
    <td></td>
    <td>1</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td></td>
    <td></td>
    <td>5</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td>dh</td>
    <td></td>
    <td>9</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td>dh</td>
    <td>tyfg</td>
    <td>4</td>
  </tr>
  <tr>
    <td>a</td>
    <td>dfhgf</td>
    <td></td>
    <td></td>
    <td>7</td>
  </tr>
  <tr>
    <td>a</td>
    <td>dfhgf</td>
    <td>fdsg</td>
    <td></td>
    <td>2</td>
  </tr>
</table>

Does anyone have a smart XSLT that can do this?

+3
2

, ( ), html

<xsl:template match="/">
    <html>
        <head>
        </head>
        <body>
            <table>
                <xsl:apply-templates select="//node" mode="row" />
            </table>
        </body>
    </html>
</xsl:template>

<xsl:template match="node" mode="row">
    <tr>
        <xsl:apply-templates select="ancestor-or-self::node" mode="popcell"/>   
        <xsl:apply-templates select="node[1]" mode="emptycell"/>
    </tr>
</xsl:template>

<xsl:template match="node" mode="popcell">
    <td><xsl:value-of select="@text"/></td>
</xsl:template>

<xsl:template match="node" mode="emptycell">
    <td></td>
    <xsl:apply-templates select="node[1]" mode="emptycell"/>
</xsl:template>

2: , : P, :

<xsl:variable name="depth">
    <xsl:for-each select="//node">
        <xsl:sort select="count(ancestor::node)" data-type="number" order="descending"/>
        <xsl:if test="position()=1">
            <xsl:value-of select="count(ancestor::node)+1"/>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

<xsl:template match="/">
    <html>
        <head>
        </head>
        <body>
            <table>
                <xsl:apply-templates select="//node" mode="row" />
            </table>
        </body>
    </html>
</xsl:template>

<xsl:template match="node" mode="row">
    <tr>
        <xsl:apply-templates select="ancestor-or-self::node" mode="popcell"/>
        <xsl:call-template name="emptycells">
            <xsl:with-param name="n" select="($depth)-count(ancestor-or-self::node)"/>
        </xsl:call-template>
        <td><xsl:value-of select="@value"/></td>
    </tr>
</xsl:template>

<xsl:template match="node" mode="popcell">
    <td><xsl:value-of select="@text"/></td>
</xsl:template>

<xsl:template name="emptycells">
    <xsl:param name="n" />
    <xsl:if test="$n &gt; 0">
        <td></td>   
        <xsl:call-template name="emptycells">
            <xsl:with-param name="n" select="($n)-1"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>
+3

XSLT 1.0 .

  • HTML

XSLT:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

  <!-- some preparation -->
  <xsl:variable name="vAllNodes" select="//node" />

  <!-- find out the deepest nested node -->
  <xsl:variable name="vMaxDepth">
    <xsl:for-each select="$vAllNodes">
      <xsl:sort 
        select="count(ancestor::node)" 
        data-type="number" 
        order="descending" 
      />
      <xsl:if test="position() = 1">
        <xsl:value-of select="count(ancestor-or-self::node)" />
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <!-- select a list of nodes, merely to iterate over them -->
  <xsl:variable name="vIteratorList" select="
    $vAllNodes[position() &lt;= $vMaxDepth]
  " />

  <!-- build the table -->
  <xsl:template match="/">
    <table>
      <!-- the rows will be in document order -->
      <xsl:apply-templates select="$vAllNodes" />
    </table>
  </xsl:template>

  <!-- build the rows -->
  <xsl:template match="node">
    <xsl:variable name="self" select="." />
    <tr>
      <!-- iteration instead of recursion -->
      <xsl:for-each select="$vIteratorList">
        <xsl:variable name="vPos" select="position()" />
        <td>
          <!-- the ancestor axis is indexed the other way around -->
          <xsl:value-of select="
            $self/ancestor-or-self::node[last() - $vPos + 1]/@text
          " />
        </td>
      </xsl:for-each>
      <td>
        <xsl:value-of select="@value" />
      </td>
    </tr>
  </xsl:template>

</xsl:stylesheet>

:

<table>
  <tr>
    <td>a</td>
    <td></td>
    <td></td>
    <td></td>
    <td>1</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td></td>
    <td></td>
    <td>5</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td>dh</td>
    <td></td>
    <td>9</td>
  </tr>
  <tr>
    <td>a</td>
    <td>gga</td>
    <td>dh</td>
    <td>tyfg</td>
    <td>4</td>
  </tr>
  <tr>
    <td>a</td>
    <td>dfhgf</td>
    <td></td>
    <td></td>
    <td>7</td>
  </tr>
  <tr>
    <td>a</td>
    <td>dfhgf</td>
    <td>fdsg</td>
    <td></td>
    <td>2</td>
  </tr>
</table>
0

Source: https://habr.com/ru/post/1709758/


All Articles