如何在XSLT中进行循环?

时间:2011-03-14 19:56:51

标签: c# .net xml xslt

我有以下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 个答案:

答案 0 :(得分:4)

使用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>

答案 1 :(得分:3)

这是一个直接的转变:

<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 :(得分:2)

这个完整的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. 标识规则由三个模板覆盖,每个模板与特定类型的元素(顶部元素Articleline)匹配,并简单地将元素重命名为: ordersorderorder_line

答案 3 :(得分:1)

这只是我的头脑,但我认为你可以这样做:

<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循环,没有用于计数器的循环。

答案 4 :(得分:0)

您的源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>

答案 5 :(得分:0)

在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>

答案 6 :(得分:0)

试试这个,但我不是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>