C# 如何在XSLT中进行循环?

C# 如何在XSLT中进行循环?,c#,.net,xml,xslt,C#,.net,Xml,Xslt,我有以下XML结构: <Article> <id>1</id> <line>L11</line> <line>L12</line> <line>L13</line> </Article> <Article> <id>2</id>

我有以下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>

1.
L11
L12
L13
2.
L21
L22
L23
我想使用XSLT一次只迭代一篇文章的所有行,这样我就可以实现以下结构:(每一篇文章都转换为一个顺序,其行在新结构中转换为行结构)


1.
L11
L12
L13
2.
L21
L22
L23

这只是我的想法,但我认为你可以这样做:

<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循环。

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

使用XSLT,尝试将手头的任务看作是一组必须匹配的模式或规则,以及每次遇到此类模式时要采取的操作。您通常可以让运行时担心循环等问题来发现模式

在您的具体案例中,您已经描述了两种需要特殊逻辑的模式。每次出现元素
文章
,您都希望应用规则将其名称更改为
顺序
。 每当元素
作为
文章
的子元素出现时,请将其替换为
订单行
。对于任何其他模式,您只需复制原始文档中的内容:

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

这是一个简单的转换:

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

编辑:一个通用的根元素规则。

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

试试这个,但我不是xslt专家:)




这个完整的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>
<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>

应用于提供的XML文档时(包装到单个顶部元素中以使其格式良好):


1.
L11
L12
L13
2.
L21
L22
L23
生成所需的正确结果:

<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>
<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.
L11
L12
L13
2.
L21
L22
L23
说明

  • 标识规则“按原样”复制每个节点

  • 标识规则由三个模板覆盖,每个模板匹配一种特定类型的元素(顶部元素,
    Article
    line
    ),并分别将元素重命名为:
    orders
    order
    order\u line


  • 非常接近<代码>与
    相同。另外,除非您为属性声明了规则,否则不要将模板应用于属性节点。@Alejandro,谢谢您的帮助。我根据自己使用属性的脚本改编了这个。我把它们删掉是为了简化,看起来我删掉的不够多!如果我的内部XSLT解析器是正确的,这将在关闭
    标记后放置
    ,这不是他想要的。此外,这是一个非常好的解决方案。
    /
    不是有效的XPath/XSLT表达式。真的吗?我似乎记得我成功地使用过它。但是我的记忆可以欺骗我,不管怎样,我把它改成了我认为有同样效果的东西。这在很大程度上是我的想法。作为一名未成年人,不需要启动
    /
    孩子::
    。对于几乎每一个XSLT问题,你应该首先问自己,“我可以通过使用身份转换来完成吗?”答案是“是”,大部分时间是这样的,从标识转换开始,您就可以使用XSLT的奇怪特性,而不是反对它。为每个元素指定一个模板并相应地采取行动,如@Eugene TalagrandGood question,+1。请参阅我的答案,以获得一个完整、简短、简单的解决方案,该解决方案基于最基本、最强大的XSLT设计模式:使用和覆盖标识规则/模板。还提供了详细的解释。
    <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>