Как использовать XSLT-рекурсию для преобразования любых данных xml в представление таблицы html: - PullRequest
3 голосов
/ 16 ноября 2010

Для данного xml мне нужно сгенерировать html-таблицу для представления значений в xml. Мне нужна рекурсия для любого ключа N, если значение N является текстом, просто распечатайте его. Если valueN равно xml, выведите (вложенную) таблицу с ее значением. Я думаю, что мое непонимание того, как правильно использовать XSLT-рекурсию, является основой вопроса. Любая помощь приветствуется.

Введите:

<root>
    <key1> Text Value  </key1>
<key2> 
    <a> aaa </a>
    <b> bbb </b>
</key2>
<keyN> valueN </keyN>
<root>

Выход:

<table border="1px">
    <tr>
        <td> key1 </td>
        <td> Text Value </td>
    </tr>

    <tr>
        <td> key2 </td>
        <td>
            <table border="1px">
                <tr> <td> a </td> <td> aaa </td> </tr>
                <tr> <td> b </td> <td> bbb </td> </tr>
            </table>
        </td>
    </tr>

    <tr> 
        <td> keyN </td>
        <td>
            valueN (if valueN is text)
                    OR
            <table> ... </table> (if valueN is xml)
        <td>
    </tr>
</table>

Ответы [ 5 ]

5 голосов
/ 16 ноября 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/*//*[1]">
        <table border="1">
            <xsl:call-template name="makeRow"/>
        </table>
    </xsl:template>
    <xsl:template match="*" name="makeRow">
        <tr>
            <td>
                <xsl:value-of select="name()"/>
            </td>
            <td>
                <xsl:apply-templates select="node()[1]"/>
            </td>
        </tr>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="/*">
        <xsl:apply-templates select="node()[1]"/>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<table border="1">
    <tr>
        <td>key1</td>
        <td> Text Value  </td>
    </tr>
    <tr>
        <td>key2</td>
        <td>
            <table border="1">
                <tr>
                    <td>a</td>
                    <td> aaa </td>
                </tr>
                <tr>
                    <td>b</td>
                    <td> bbb </td>
                </tr>
            </table></td>
    </tr>
    <tr>
        <td>keyN</td>
        <td> valueN </td>
    </tr>
</table>

Примечание : используется мелкозернистый шаблон обхода.Три правила: «первый дочерний потомок корневого элемента», вывод table и вызов makeRow;makeRow (соответствует любому элементу, который не является ни первым дочерним потомком, ни корневым элементом), выведите tr и ячейки таблицы с именем и первым дочерним рисунком, затем примените шаблоны к следующему брату;правило корневого элемента, начните мелкозернистый обход.

3 голосов
/ 16 ноября 2010

Это преобразование :

<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="/*">
  <table border="1px">
   <xsl:apply-templates/>
  </table>
 </xsl:template>

 <xsl:template match="*[*][parent::*]">
     <tr>
      <td><xsl:value-of select="name()"/></td>
      <td>
        <table border="1px">
          <xsl:apply-templates/>
        </table>
      </td>
     </tr>
 </xsl:template>

 <xsl:template match="*[not(*)]">
   <tr>
      <td><xsl:value-of select="name()"/></td>
    <td><xsl:value-of select="."/></td>
   </tr>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному XML-документу :

<root>
    <key1> Text Value  </key1>
    <key2>
        <a> aaa </a>
        <b> bbb </b>
    </key2>
    <keyN> valueN </keyN>
</root>

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

<table border="1px">
   <tr>
      <td>key1</td>
      <td> Text Value  </td>
   </tr>
   <tr>
      <td>key2</td>
      <td>
         <table border="1px">
            <tr>
               <td>a</td>
               <td> aaa </td>
            </tr>
            <tr>
               <td>b</td>
               <td> bbb </td>
            </tr>
         </table>
      </td>
   </tr>
   <tr>
      <td>keyN</td>
      <td> valueN </td>
   </tr>
</table>

Обратите внимание на силу XSLT :

  1. Нет явной рекурсии .

  2. Никаких условий внутри какого-либо шаблона .

  3. Полностью стиль обработки .

0 голосов
/ 17 февраля 2012

ДОБАВЛЕННАЯ ФУНКЦИОНАЛЬНОСТЬ ДЛЯ ОТОБРАЖЕНИЯ АТРИБУТОВ

    <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:template match="/*//*[1]">
            <table border="1">
                <xsl:call-template name="makeRow" />
            </table>
        </xsl:template>
        <xsl:template match="*" name="makeRow">
            <tr>
                <td><xsl:value-of select="name()" /> <xsl:if
                    test="count(@*) > 0">
                    <table>
                        <xsl:apply-templates select="@*" />
                    </table>
                </xsl:if></td>
                <td><xsl:apply-templates select="node()[1]" /></td>
            </tr>
            <xsl:apply-templates select="following-sibling::node()[1]" />
        </xsl:template>
        <xsl:template match="/*">
            <xsl:apply-templates select="node()[1]" />
        </xsl:template>
        <xsl:template match="@*">
            <tr>
                <td>@<xsl:value-of select="name()" /></td>
                <td><xsl:value-of select="." /></td>
            </tr>
        </xsl:template>
    </xsl:stylesheet>
0 голосов
/ 16 ноября 2010

Это звучит как домашнее задание: -)

Вы работаете с двумя вещами здесь:

  1. Элементы с произвольным именем, к которым необходимо применить шаблон XSLT, и
  2. Определение типа содержимого элемента (текст или фрагмент XML).

Вы хотите использовать шаблон, который может произвольно сопоставлять элементы в вашем XML (то есть не элементы с определенным именем). <xsl:template match="*"> будет соответствовать всем элементам в вашем XML-документе.

Когда вы сталкиваетесь с элементом, вам нужно создать таблицу:

<xsl:template match="*">
  <table border="1px">
  </table>
</xsl:template>

Теперь мы хотим выяснить, имеем ли мы дело с фрагментом XML (элементом) или фрагментом текста. Для этого мы подходим на node(). Помните, что узел может быть элементом, текстом, пробелом, инструкцией обработки или комментарием в документе XML. Когда вы сопоставили узел, вы хотите создать новую строку таблицы и отобразить имя текущего узла:

<xsl:template match="node()">
  <tr>
    <td>
      <xsl:value-of select="local-name()"/>
    </td>
  </tr>
</xsl:template>

Затем вам нужно выяснить, является ли этот узел текстовым или нет. Вы можете использовать <xsl:if> или <xsl:choose>. Я склонен предпочесть последнее. Если это текстовый узел, отобразите значение текста, иначе обработайте узел как фрагмент XML и снова вызовите наш начальный шаблон (это рекурсивная часть).

...
<xsl:choose>
  <xsl:when test="current() = text()">
    <td>
      <xsl:value-of select="." />
    </td>
  </xsl:when>
  <xsl:otherwise>
    <td>
      <xsl:apply-templates select="*" mode="table"/>
    </td>
  </xsl:otherwise>
</xsl:choose>
...

Вот окончательное решение.

<xsl:template match="/root">
  <xsl:apply-templates select="*" mode="table" />
</xsl:template>

<xsl:template match="*" mode="table">
  <table border="1px">
    <xsl:apply-templates select="." mode="table-row" />
  </table>
</xsl:template>

<xsl:template match="node()" mode="table-row">
  <tr>
    <td>
      <xsl:value-of select="local-name()"/>
    </td>
    <xsl:choose>
      <xsl:when test="current() = text()">
        <td>
          <xsl:value-of select="." />
        </td>
      </xsl:when>
      <xsl:otherwise>
        <td>
          <xsl:apply-templates select="*" mode="table"/>
        </td>
      </xsl:otherwise>
    </xsl:choose>
  </tr>
</xsl:template>

Я использую атрибут mode в шаблоне, поскольку элемент также является узлом в документе XML, и <xsl:apply-templates select="*"/> будет соответствовать как <xsl:template match="*">, так и <xsl:template match="node()">. Использование атрибута mode устраняет неоднозначность.

0 голосов
/ 16 ноября 2010
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <body>
                <!-- apply root as a table -->
                <xsl:apply-templates select="root" mode="table"/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="node()[not(self::text())]" mode="table">
        <table border="1px">
            <!-- create table and process children as rows -->
            <xsl:apply-templates select="node()" mode="row"/>
        </table>
    </xsl:template>

    <xsl:template match="node()[not(self::text())]" mode="row">
        <tr>
            <!-- make decision here. 
                 If row contains only text - apply is as a simple row
                 In case there are some other nodes proces them as a table.
           -->
            <xsl:choose>
                <xsl:when test=". = text()">
                    <xsl:apply-templates select="." mode="column"/>
                </xsl:when>
                <xsl:otherwise>
                    <td><xsl:value-of select="name()"/></td>
                    <td><xsl:apply-templates select="." mode="table"/></td>
                </xsl:otherwise>
            </xsl:choose>
        </tr>
    </xsl:template>

    <xsl:template match="node()" mode="column">
        <td><xsl:value-of select="name()"/></td>
        <td><xsl:value-of select="."/></td>
    </xsl:template>
</xsl:stylesheet>

Выход:

<html>
    <body>
        <table border="1px">
            <tr>
                <td>key1</td>
                <td>Text Value</td>
            </tr>

            <tr>
                <td>key2</td>
                <td>
                <table border="1px">
                    <tr>
                        <td>a</td>
                        <td>aaa</td>
                    </tr>

                    <tr>
                        <td>b</td>
                        <td>bbb</td>
                    </tr>
                </table>
                </td>
            </tr>

            <tr>
                <td>keyN</td>
                <td>valueN</td>
            </tr>

        </table>
    </body>
</html>

Кстати, лучше будет переписать xsl: выберите два отдельных шаблона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...