XSLT для выравнивания иерархии XML в таблицу HTML - PullRequest
3 голосов
/ 04 июня 2009

У меня есть некоторый иерархический 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>

Имена элементов одинаковы до конца («узел»), а глубина иерархии заранее неизвестна - в приведенном выше примере самый глубокий лист равен четырем, но он может быть глубина.

Что мне нужно сделать, так это взять этот XML и сплющить его в таблицу HTML. Количество столбцов в таблице должно равняться глубине самого глубокого элемента плюс столбец для атрибута значения каждого элемента. «Значение» должно появиться в крайнем правом столбце таблицы, поэтому выходные строки не могут иметь неровных краев. Должна быть строка для каждого узла независимо от того, на каком уровне он находится. Приведенный выше пример должен быть преобразован в:

<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>

У кого-нибудь есть какой-нибудь умный XSLT, который может этого добиться?

Ответы [ 2 ]

3 голосов
/ 04 июня 2009

Это не совсем то, что вам нужно (потому что он оставляет зазубренную таблицу), но все равно будет работать в 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>
0 голосов
/ 04 июня 2009

Это решение 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...