как сделать зацикливание в XSLT? - PullRequest
2 голосов
/ 14 марта 2011

У меня есть следующая структура XML:

    <Article>
         <id>1</id>
         <line>L11</line>
         <line>L12</line>
         <line>L13</line>
     </Article>
    <Article>
         <id>2</id>
         <line>L21</line>
         <line>L22</line>
         <line>L23</line>
     </Article>

Я хочу использовать XSLT для итерации по всем строкам только одной статьи за раз, чтобы я мог получить следующую структуру: (каждая статья преобразуется в порядок, а ее строки преобразуются в строчные структуры в новом структура)

        <orders>
           <order>
              <id>1</id>
              <order_line>L11</order_line>
              <order_line>L12</order_line>
              <order_line>L13</order_line>
            </order>
           <order>
              <id>2</id>
              <order_line>L21</order_line>
              <order_line>L22</order_line>
              <order_line>L23</order_line>
            </order>
        </orders>

Ответы [ 7 ]

4 голосов
/ 14 марта 2011

Используя XSLT, попытайтесь представить стоящую перед вами задачу как набор шаблонов или правил, которым вы должны соответствовать, и действия, которые необходимо предпринимать при каждом обнаружении такого шаблона. Обычно вы можете позволить среде выполнения беспокоиться о циклах и т. Д., Чтобы обнаружить шаблоны.

В вашем конкретном случае вы описали два шаблона, для которых требуется особая логика. Каждый раз, когда появляется элемент Article, вы хотите применить правило, чтобы изменить его имя на order. Каждый раз, когда элемент line встречается как дочерний элемент Article, заменяйте его на order_line. Для любого другого шаблона вы просто хотите скопировать содержимое, как оно было в исходном документе:

<!-- Match element Article, and whenever it's encountered, insert an 'order' element, and copy the contents of Article -->
<xsl:template match="Article">
  <order> <xsl:apply-templates/> </order>
</xsl:template>

<!-- Match element 'line', and whenever it's encountered, insert an 'order_line' element, and copy the contents -->
<xsl:template match="Article/line">
  <order_line> <xsl:apply-templates/> </order_line>
</xsl:template>

<!-- Match any other element we haven't specified explicity, and copy it verbatim -->
<xsl:template match="node()">
  <xsl:copy>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>
3 голосов
/ 14 марта 2011

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/*">
        <orders>
            <xsl:apply-templates/>
        </orders>
    </xsl:template>
    <xsl:template match="Article">
        <order>
            <xsl:apply-templates/>
        </order>
    </xsl:template>
    <xsl:template match="line">
        <order_line>
            <xsl:apply-templates/>
        </order_line>
    </xsl:template>
    <xsl:template match="id">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

РЕДАКТИРОВАТЬ : общее правило корневого элемента.

2 голосов
/ 15 марта 2011

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

<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="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
  <orders>
   <xsl:apply-templates/>
  </orders>
 </xsl:template>

 <xsl:template match="Article">
  <order>
   <xsl:apply-templates/>
  </order>
 </xsl:template>

 <xsl:template match="line">
  <order_line>
   <xsl:apply-templates/>
  </order_line>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному XML-документу (обернутый в один верхний элемент, чтобы сделать его правильно сформированным):

<t>
    <Article>
        <id>1</id>
        <line>L11</line>
        <line>L12</line>
        <line>L13</line>
    </Article>
    <Article>
        <id>2</id>
        <line>L21</line>
        <line>L22</line>
        <line>L23</line>
    </Article>
</t>

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

<orders>
   <order>
      <id>1</id>
      <order_line>L11</order_line>
      <order_line>L12</order_line>
      <order_line>L13</order_line>
   </order>
   <order>
      <id>2</id>
      <order_line>L21</order_line>
      <order_line>L22</order_line>
      <order_line>L23</order_line>
   </order>
</orders>

Объяснение

  1. Правило идентификации копирует каждый узел "как есть".

  2. Правило идентификации переопределяется тремя шаблонами, каждый из которых соответствует элементу определенного типа (верхний элемент, Article и line) и просто переименовывает элемент, соответственно: orders, order и order_line.

1 голос
/ 14 марта 2011

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

<orders>
<xsl:for-each select="//Article">
  <order>
   <id><xsl:value-of select="./id"/></id>
   <xsl:for-each select="./line">
     <order_line><xsl:value-of select="child::text()" /></order_line>
   </xsl:for-each>
  </order>
</xsl:for-each>
</orders>

В любом случае, этого должно быть достаточно, чтобы вы начали.В XSLT есть только цикл for-each, но цикл for со счетчиком отсутствует.

0 голосов
/ 14 марта 2011

Попробуйте, но я не эксперт по xslt:)

<?xml version="1.0" encoding="utf-8"?>

<xsl:template match="/" name="A">
    <orders>
        <xsl:for-each select="Articles/Article">
            <order>
                <id>
                    <xsl:value-of select="id" />
                </id>
                <xsl:for-each select="line">
                    <order_line>
                        <xsl:value-of select="node()"></xsl:value-of>
                    </order_line>
                </xsl:for-each>
            </order>
        </xsl:for-each>
    </orders>
</xsl:template>

0 голосов
/ 14 марта 2011

Правильный способ сделать «зацикливание» в XSLT - позволить процессору XSLT пройтись по дереву документов за вас. Все остальное борется против природы XSLT.

Вот (почти) полное решение:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <orders><xsl:apply-templates/></orders>
    </xsl:template>
    <xsl:template match="Article">
        <order>
            <id><xsl:value-of select="id"/></id>
            <xsl:apply-templates select="line"/>
        </order>
    </xsl:template>
    <xsl:template match="Article/line">
        <order_line><xsl:value-of select="."/></order_line>
    </xsl:template>
</xsl:stylesheet>
0 голосов
/ 14 марта 2011

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

<!-- change the template match xpath to whatever the root xpath is in your document -->
<xsl:template match="root">
    <orders>
        <!-- loop over each Article -->
        <xsl:for-each select="Article">
            <order>
                <!-- pass id through -->
                <xsl:copy-of select="id"/>
                <!-- loop over each line -->
                <xsl:for-each select="line">
                    <!-- create an <order_line> node -->
                    <order_line>
                        <!-- get the value of the current <line> -->
                        <xsl:value-of select="."/>
                    </order_line>
                </xsl:for-each>
            </order>
        </xsl:for-each>
    </orders>
</xsl:template>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...