XML до HTML Таблицы, использующие XSLT или любой другой метод - PullRequest
0 голосов
/ 20 января 2020

У меня есть файл XML, который содержит следующие данные XML.

<group1>
<item1>val1</item1>
<item2>val2</item2>
<group2>
    <item3>val3</item3>
    <item4>val4</item4>
    <group3>
        <item5>val5</item5>
    </group3>
</group2>
<group2>
    <item3>val6</item3>
    <item4>val7</item4>
    <group3>
        <item5>val8</item5>
    </group3>
</group2>
<group4>
    <item6>val9</item6>
    <item7>val10</item7>
</group4>
<group4>
    <item6>val11</item6>
    <item7>val12</item7>
</group4>

до HTML таблица типа

<table --for group1>
    <tr>
        <th>item1</th>
        <th>item2</th>
    </tr>
    <tr>
        <td>val1</td>
        <td>val2</td>
    </tr>
</table>

<table --for group2>
    <tr>
        <th>item3</th>
        <th>item4</th>
    </tr>
    <tr>
        <td>val3</td>
        <td>val4</td>
    </tr>
</table>

<table --for group3>
    <tr>
        <th>item5</th>
    </tr>
    <tr>
        <td>val5</td>
    </tr>
</table>

<table --for group2>
    <tr>
        <th>item3</th>
        <th>item4</th>
    </tr>
    <tr>
        <td>val6</td>
        <td>val7</td>
    </tr>
</table>

<table --for group3>
    <tr>
        <th>item5</th>
    </tr>
    <tr>
        <td>val8</td>
    </tr>
</table>

<table --for group4>
    <tr>
        <th>item6</th>
        <th>item7</th>
    </tr>
    <tr>
        <td>val9</td>
        <td>val10</td>
    </tr>
    <tr>
        <td>val11</td>
        <td>val12</td>
    </tr>
</table>

In group1 есть две group2, которые имеют внутри себя group3. Таким образом, каждая группа 2 должна быть отдельной таблицей, за которой следует таблица группы 3. Есть две группы, но внутри них нет другой группы. Таким образом, обе группы 4 должны быть в одной таблице.

Примечание: Каждая группа может иметь любое количество групп, вложенных в них.

То, чего я пытаюсь достичь, это отображать результаты запросов, как в Oracle представлении таблицы модели данных bi publisher.

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <HTML>
        <BODY>
            <xsl:apply-templates />
        </BODY>
    </HTML>
</xsl:template>
<xsl:template match="/*">
    <TABLE BORDER="1">
        <TR>
            <xsl:for-each select="*/*">
                <xsl:choose>
                    <xsl:when test="child::*">
                        <!-- <h1>
                            <xsl:value-of select="local-name()" />
                        </h1> -->
                    </xsl:when>
                    <xsl:otherwise>
                        <!-- <h1>
                        <xsl:value-of select="local-name()" />
                    </h1> -->
                        <xsl:for-each select=".">
                            <TD>
                                <xsl:value-of select="local-name()" />
                            </TD>
                        </xsl:for-each>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
            <xsl:apply-templates />
        </TR>
    </TABLE>
</xsl:template>
<xsl:template match="/*/*">
    <TR>
        <xsl:for-each select="*">
            <xsl:choose>
                <xsl:when test="child::*">
                    <h1>
                        <xsl:value-of select="local-name()" />
                    </h1>
                </xsl:when>
                <xsl:otherwise>
                    <td>
                        <xsl:apply-templates select="." />
                    </td>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </TR>
</xsl:template>
<!-- <xsl:template match="/*/*/*">
    <xsl:choose>
        <xsl:when test="child::*">
            <TABLE BORDER="1">
                <TR>
                    <xsl:for-each select="*/*">
                        <TD>
                            <xsl:value-of select="local-name()" />
                        </TD>
                    </xsl:for-each>
                </TR>
            </TABLE>
            <xsl:value-of select="." />
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="." />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template> -->

1 Ответ

1 голос
/ 20 января 2020

Кажется, по большей части вы просто хотите сгладить вложенную иерархию, поэтому используйте для этого рекурсию. Кроме того, чтобы объединить / сгруппировать самый глубокий уровень, используйте группирование, например, в XSLT 1, с группировкой по Мюнхену и ключом:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

  <xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>

  <xsl:key name="table-group"
    match="*[* and not(*/*)]"
    use="concat(generate-id(..), '|', local-name())"/>

  <xsl:template match="*[*]">
      <table>
          <thead>
              <tr>
                  <xsl:apply-templates select="*[not(*)]" mode="header"/>
              </tr>
          </thead>
          <tbody>
              <tr>
                  <xsl:apply-templates select="*[not(*)]"/>
              </tr>
          </tbody>
      </table>
      <xsl:apply-templates select="*[*/*]"/>
      <xsl:apply-templates
        select="*[* and not(*/*)][generate-id() = generate-id(key('table-group', concat(generate-id(..), '|', local-name()))[1])]" mode="merge-groups"/>
  </xsl:template>

  <xsl:template match="*[not(*)]" mode="header">
      <th>
          <xsl:value-of select="local-name()"/>
      </th>
  </xsl:template>

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

  <xsl:template match="*[*]" mode="merge-groups">
      <table>
          <thead>
              <tr>
                  <xsl:apply-templates select="*[not(*)]" mode="header"/>
              </tr>
          </thead>
          <tbody>
              <xsl:apply-templates select="key('table-group', concat(generate-id(..), '|', local-name()))" mode="row"/>
          </tbody>
      </table>
  </xsl:template>

  <xsl:template match="*" mode="row">
      <tr>
          <xsl:apply-templates select="*"/>
      </tr>
  </xsl:template>

  <xsl:template match="/">
    <html>
      <head>
        <title>.NET XSLT Fiddle Example</title>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ncnu9AZ/1

Если Вы новичок в мюнхенской группировке в XSLT 1, пожалуйста, используйте любой учебник или онлайн-введение по мюнхенской группировке в XSLT 1, чтобы познакомить вас с этим подходом, один онлайн-источник - http://www.jenitennison.com/xslt/grouping/muenchian.html.

В приведенной выше таблице стилей, поскольку необходимо сгруппировать элементы, не вложенные далее только в контексте родительского контейнера, используемый ключ включает в себя сгенерированный идентификатор родительского элемента (generate-id(...)). Поэтому вызов key('table-group', concat(generate-id(..), '|', local-name())) в контексте элемента дает нам набор узлов с группой элементов с одинаковым именем внутри одного и того же родителя. И с целым предикатом [generate-id() = generate-id(key('table-group', concat(generate-id(..), '|', local-name()))[1])] мы просто устанавливаем sh, что первый элемент в порядке документов в этом наборе узлов в настоящее время обрабатывается. generate-id() = generate-id(key(...)[1]) - это в основном способ XSLT 1 для выражения того, что можно сделать в XSLT 2 или более поздней версии, как . is key(...)[1], то есть для проверки идентичности узла элемента контекста в предикате и первого узла, возвращенного этим key(...) звоните.

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