XSLT для динамических вложенных XML-таблиц

#xml #xslt #xsl-stylesheet

#xml #xslt #xsl-таблица стилей

Вопрос:

Я новичок в xslt и столкнулся с проблемой, поскольку я динамически сгенерировал XML-файл (т. Е. Имена узлов неизвестны) И пробовал много подходов для просмотра содержимого во вложенных таблицах в html-файле с использованием xslt, но все мои усилия терпят неудачу.

 <?xml version="1.0" encoding="UTF-8"?>
<content>
    <Source>
        <Column1>Name</Column1>
        <Column2>Organization Name</Column2>
        <SubSource>
            <Column1>Name</Column1>
            <Column2>Person Name</Column2>
            <Column1>Address</Column1>
            <Column2>House: E5, Block-G, Road-02</Column2>
            <Details>
                <Column1>Entry date</Column1>
                <Column2>6/6/13 12:04 PM</Column2>
                <Column1>height</Column1>
                <Column2>153</Column2>
                <Column1>weight</Column1>
                <Column2>53.5</Column2>
                <Column1>temperature</Column1>
                <Column2>98.67</Column2>
                <Column1>pulse rate</Column1>
                <Column2>76</Column2>
                <Advices>
                    <Advice>
                        <Column1>Title</Column1>
                        <Column2>Workout</Column2>
                        <Column1>Location</Column1>
                        <Column2>In the Park</Column2>
                    </Advice>
                    <Advice>
                        <Column1>Title</Column1>
                        <Column2>Eating Habit</Column2>
                        <Column1>Remarks</Column1>
                        <Column2>Eat Less</Column2>
                        <Column1>Notes</Column1>
                        <Column2>Avoid salts</Column2>
                    </Advice>
                </Advices>
            </Details>
        </SubSource>
    </Source>
    <Source>
        <Column1>Name</Column1>
        <Column2>Organization Name</Column2>
        <SubSource>
            <Column1>Name</Column1>
            <Column2>Person Name</Column2>
            <Column1>Address</Column1>
            <Column2>House: E5, Block-G, Road-02</Column2>
            <Details>
                <Column1>Entry date</Column1>
                <Column2>6/6/13 12:04 PM</Column2>
                <Column1>height</Column1>
                <Column2>153</Column2>
                <Column1>weight</Column1>
                <Column2>53.5</Column2>
                <Column1>temperature</Column1>
                <Column2>98.67</Column2>
                <Column1>pulse rate</Column1>
                <Column2>76</Column2>
                <Advices>
                    <Advice>
                        <Column1>Title</Column1>
                        <Column2>Workout</Column2>
                        <Column1>Location</Column1>
                        <Column2>In the Park</Column2>
                    </Advice>
                </Advices>
            </Details>
        </SubSource>
    </Source>
</content>
  

Я использовал несколько подходов xslt. Однако все они не просматривают данные так, как требуется, либо меньше, либо не в таблице правильного формата!!!

Моим лучшим подходом было следующее (я не делал дизайн с несколькими таблицами, так как хотел сначала получить все данные)

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html"/>
    <xsl:template match="/">
        <html>
            <body>
                <table>
                    <xsl:apply-templates select="content/Source"/>
                </table>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="content/Source">
        <xsl:variable name="column" select="content/Source"/>
        <tr>
            <td>
                <xsl:value-of select="Column1"/>
            </td>
            <td>
                <xsl:value-of select="Column2"/>
            </td>
        </tr>
        <xsl:apply-templates select="SubSource"/>
    </xsl:template>
    <xsl:template match="SubSource">
        <tr>
            <td>
                <xsl:value-of select="Column1"/>
            </td>
            <td>
                <xsl:value-of select="Column2"/>
            </td>
        </tr>
        <xsl:apply-templates select="Details"/>
    </xsl:template>
    <xsl:template match="Details">
        <tr>
            <td>
                <xsl:value-of select="Column1"/>
            </td>
            <td>
                <xsl:value-of select="Column2"/>
            </td>
        </tr>
        <xsl:apply-templates select="Advices"/>
    </xsl:template>
    <xsl:template match="Advices">
        <xsl:for-each select="Advice">
            <tr>
                <td>
                    <xsl:value-of select="Column1"/>
                </td>
                <td>
                    <xsl:value-of select="Column2"/>
                </td>
            </tr>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>
  

И результат:

  <table>
         <tr>
            <td>Name</td>
            <td>Organization Name</td>
         </tr>
         <tr>
            <td>Name</td>
            <td>Person Name</td>
         </tr>
         <tr>
            <td>Entry date</td>
            <td>6/6/13 12:04 PM</td>
         </tr>
         <tr>
            <td>Title</td>
            <td>Workout</td>
         </tr>
         <tr>
            <td>Title</td>
            <td>Eating Habit</td>
         </tr>
         <tr>
            <td>Name</td>
            <td>Organization Name</td>
         </tr>
         <tr>
            <td>Name</td>
            <td>Person Name</td>
         </tr>
         <tr>
            <td>Entry date</td>
            <td>6/6/13 12:04 PM</td>
         </tr>
         <tr>
            <td>Title</td>
            <td>Workout</td>
         </tr>
      </table>
  

Моя цель — получить макет таблицы, аналогичный структурированному XML.

Советы по улучшению формата XML всегда приветствуются!

Спасибо

Ответ №1:

Эта таблица стилей XSLT 1.0 делает то, что вы, кажется, хотите: она создает вложенные HTML-таблицы из структуры неизвестных имен элементов.

I единственным предварительным условием является наличие <Column1> элементов, за которыми, возможно, следует связанный <Column2> .

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

  <xsl:output method="html" indent="yes" />

  <!-- #1: anything that has <Column1> children becomes a table -->
  <xsl:template match="*[Column1]">
    <table class="{name()}">
      <xsl:apply-templates select="*" mode="nested" />
    </table>
  </xsl:template>

  <!-- #2: ...if it's nested, it is wrapped in a table row first -->
  <xsl:template match="*[Column1]" mode="nested">
    <tr>
      <td colspan="2">
        <!-- this actually executes #1 because it uses no mode! -->
        <xsl:apply-templates select="." />
      </td>
    </tr>
  </xsl:template>

  <!-- #3: <Column1> governs the creation of table rows -->
  <xsl:template match="*[Column1]/Column1" mode="nested">
    <tr>
      <td><xsl:value-of select="." /></td>
      <td><xsl:value-of select="following-sibling::*[1][self::Column2]" /></td>
    </tr>
  </xsl:template>

  <!-- #4: suppress any other data field (like <Column2>) -->
  <xsl:template match="*[Column1]/*[not(*)]" mode="nested" />

</xsl:stylesheet>
  

Обратите внимание на использование режимов шаблонов: если существует более одного шаблона, который может соответствовать определенному элементу, вы можете использовать mode для различения между ними.

В этом случае вы хотите создать вложенные таблицы. На корневом уровне (вариант по умолчанию) вы можете просто создать <table> элемент.

Однако, если вы уже находитесь внутри a <table> , сначала вы должны создать <tr> / <td> , но после этого процесс тот же.

Используя режимы, я могу убедиться, что правильный шаблон выполняется в правильном контексте, без необходимости повторяться, когда дело доходит до создания фактического <table> .

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


following-sibling::*[1][self::Column2] является «первым следующим родственным, но только если он на самом деле является <Column2> .


Шаблон # 4 необходим, поскольку довольно неопределенный <xsl:apply-templates select="*" mode="nested" /> также применяется к <Column2> . Однако на самом деле они уже обрабатываются # 3, что означает, что если мы явно не подавим их, они будут генерировать нежелательные повторяющиеся выходные данные.

Комментарии:

1. Большое спасибо за вашу помощь @Tomalak. Однако мне пришлось удалить # 4, поскольку это приводило к тому, что данные в (Column1 и Column2) не появлялись!! Также есть небольшой поток, и я не могу понять, что его вызывает? Значение Column2 по какой-то причине повторяется после </tr> !!! <tr> <td>Name</td> <td>Organization Name</td> </tr>Organization Name

2. Если вы удалите # 4, все будет повторяться. Я написал это в своем ответе.

3. Да, вы ясно дали это понять. Однако с # 4 я получаю пустые таблицы!!! (без столбцов и строк) <table class="SubSource"><tr><td colspan="2"><table class="Details"><tr><td colspan="2"><table class="Advice"></table>

4. Ну, я этого не делаю. Сравните: xmlplayground.com/CyZs9O , он использует именно ваш входной образец и именно XSLT из моего ответа. Ошибка должна быть где-то в другом месте.

5. Кажется, у меня возникли некоторые проблемы в моей среде разработки. Протестировал его на w3schools, и он работает отлично. Большое спасибо @Tomalak за помощь и объяснение метода.