Как получить все подузлы документа XML? - PullRequest
1 голос
/ 02 июля 2010

У меня есть XML-документ, который моделирует эту иерархию задач:

1     Customer
1.1   Product A
1.1.1 Task Alpha
1.1.2 Task Beta
1.2   Product B
1.2.1 Task Alpha
1.2.2 Task Gamma
2     Customer
2.1   Product W
2.1.1 Task Delta

Неизвестное количество клиентов, продуктов и заданий на продукт.Также может быть неизвестное количество подзадач, поэтому мы могли бы видеть это:

19.16.8.17.1 Subtask Something

XML выглядит так:

<ROWSET>
    <ROW>
        <PROJECT_CODE>Don't Care</PROJECT_CODE>
    </ROW>
    <ROW>
        <PROJECT_CODE>WBS</PROJECT_CODE>
        <TASK_DETAIL>
            <TASKS>
                <TASK>
                    <TASK_CODE>1</TASK_CODE>
                    <TASK_DESCRIPTION>Customer 1</TASK_DESCRIPTION>
                    <TASKS>
                        <TASK>
                            <TASK_CODE>1.1</TASK_CODE>
                            <TASK_DESCRIPTION>Product A</TASK_DESCRIPTION>
                            <TASKS>
                                <TASK_CODE>1.1.1</TASK_CODE>
                                <TASK_DESCRIPTION>Task Alpha</TASK_DESCRIPTION>
                                <TASKS />
                                <TASK_CODE>1.1.2</TASK_CODE>
                                <TASK_DESCRIPTION>Task Beta</TASK_DESCRIPTION>
                                <TASKS />
                            </TASKS>
                        </TASK>
                        <TASK>
                            <TASK_CODE>1.2</TASK_CODE>
                            <TASK_DESCRIPTION>Product B</TASK_DESCRIPTION>
                            <TASKS>
                                <TASK_CODE>1.2.1</TASK_CODE>
                                <TASK_DESCRIPTION>Task Alpha</TASK_DESCRIPTION>
                                <TASKS />
                                <TASK_CODE>1.2.2</TASK_CODE>
                                <TASK_DESCRIPTION>Task Gamma</TASK_DESCRIPTION>
                                <TASKS />
                            </TASKS>
                        </TASK>
                    </TASKS>
                </TASK>
                <TASK>
                    <TASK_CODE>2</TASK_CODE>
                    <TASK_DESCRIPTION>Customer 2</TASK_DESCRIPTION>
                    <TASKS>
                        <TASK>
                            <TASK_CODE>2.1</TASK_CODE>
                            <TASK_DESCRIPTION>Product W</TASK_DESCRIPTION>
                            <TASKS>
                                <TASK_CODE>2.1.1</TASK_CODE>
                                <TASK_DESCRIPTION>Task Delta</TASK_DESCRIPTION>
                                <TASKS />
                            </TASKS>
                        </TASK>
                    </TASKS>
                </TASK>
            </TASKS>
        </TASK_DETAIL>
    </ROW>
</ROWSET>

Моя первая попытка XSLT заключается в следующем:

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="ROW">
    <xsl:apply-templates select="PROJECT_CODE[.='WBS']"/>
</xsl:template>
<xsl:template match="PROJECT_CODE">
    <h1><xsl:value-of select="."/></h1>
    <table>
        <tr>
            <th>Task Code</th>
            <th>Description</th>
        </tr>
        <xsl:for-each select="./../TASK_DETAIL/TASKS/TASK">
        <tr>
            <td><xsl:value-of select="TASK_CODE"/></td>
            <td><xsl:value-of select="TASK_DESCRIPTION"/></td>
        </tr>
            <xsl:for-each select="./TASKS/TASK">
                <tr>
                    <td><xsl:value-of select="TASK_CODE"/></td>
                    <td><xsl:value-of select="TASK_DESCRIPTION"/></td>
                </tr>
            </xsl:for-each>
        </xsl:for-each>
    </table>
</xsl:template>

Как видите, я очень наивный подход к разбору этой вещи.Я хотел бы перечислить все задачи и подзадачи моей конкретной WBS, независимо от того, насколько глубоко она проходит.Как мне это сделать?

Ответы [ 2 ]

3 голосов
/ 02 июля 2010

Вместо вложения xsl:for-each непосредственно объявите несколько шаблонов с помощью xsl:template и вызовите их (рекурсивно) через

  1. xsl:call-template, если вы хотите указать конкретный именованный шаблон или
  2. xsl:apply-templates если шаблон должен использоваться на основе выражения XPath (которое в вашем случае может быть таким же простым, как «задача»

Для базового использования xsl:apply-templates должно быть достаточно, ноиногда вы хотите соответствовать определенному правилу.

Я бы сделал это так (заметьте, это довольно грубо ... Я думаю, вы можете выяснить детали с небольшой помощью, например, w3schools ):

  1. один шаблон для tasks и один для task
  2. шаблон для tasks обходит узлы task и вызывает шаблон taskдля каждого task узла
  3. сам шаблон task снова вызывает шаблон tasks, если существует tasks узел
2 голосов
/ 02 июля 2010

Похоже, что Musikk опередил меня, но вот демонстрационная версия, которая делает то, что я понимаю, что вы хотите.В общем, избегайте xsl: for-each для большинства вещей, которые, по вашему мнению, следует использовать для for-each for (т.е. для которых вы бы использовали for-each на других языках).Вместо этого используйте apply-templates или call-templates, как говорит musikk.Читайте также о режимах (mode = "foo"), если вам приходится обрабатывать один и тот же контент несколько раз (например, для генерации оглавления, затем тела, а затем индекса).

    <?xml version="1.0" ?>
<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="ROW[./PROJECT_CODE='WBS']">
    <h1><xsl:value-of select="PROJECT_CODE"/></h1>
    <table>
      <tr>
        <th>Task Code</th>
        <th>Description</th>
      </tr>
      <xsl:apply-templates/>
    </table>
  </xsl:template>
  <xsl:template match="TASK">
    <tr>
      <td><xsl:value-of select="TASK_CODE"/></td>
      <td><xsl:value-of select="TASK_DESCRIPTION"/></td>
    </tr>
    <xsl:apply-templates/>
  </xsl:template>
  <xsl:template match="text()"/>
</xsl:stylesheet>

Это производит:

    <html>
   <body>
      <h1>WBS</h1>
      <table>
         <tr>
            <th>Task Code</th>
            <th>Description</th>
         </tr>
         <tr>
            <td>1</td>
            <td>Customer 1</td>
         </tr>
         <tr>
            <td>1.1</td>
            <td>Product A</td>
         </tr>
         <tr>
            <td>1.2</td>
            <td>Product B</td>
         </tr>
         <tr>
            <td>2</td>
            <td>Customer 2</td>
         </tr>
         <tr>
            <td>2.1</td>
            <td>Product W</td>
         </tr>
      </table>
   </body>
</html>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...