C# 如何在XSLT中进行循环?
我有以下XML结构: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>
<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>