2011-03-14 92 views
2

我有以下XML结构:如何在XSLT中循环?

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

好问题,+1。请参阅我的回答,以获得基于最基本且功能强大的XSLT设计模式的完整,简短易用的解决方案:使用并覆盖身份规则/模板。还提供了详细的解释。 – 2011-03-15 03:15:26

回答

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

非常接近! ''与''相同。另外,除非您为属性声明规则,否则不要将模板应用于属性节点。 – 2011-03-14 20:34:47

+0

+1对于模式匹配,顺便说一下。 – 2011-03-14 20:37:59

+0

@Alejandro,谢谢你的收获。我从我自己的一些使用属性的脚本中调整了这一点。我把它们剪掉以简化,看起来我没有足够的剪裁! – 2011-03-14 21:16:28

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循环,但没有for循环与计数器。

+0

'。/'不是有效的XPath/XSLT表达式。 – 2011-03-14 20:36:05

+0

真的吗?我似乎记得成功使用它。但是我的记忆可以欺骗我,无论如何,我将它改变成我认为具有相同效果的东西。这是我的头顶。 – 2011-03-14 20:44:20

+0

作为次要的,不需要启动'。/'或'child ::'。 – 2011-03-14 20:55:47

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

使用for-each这样的循环是很难做到的。为每个元素指定一个模板并采取相应的行动,如@Eugene Talagrand – 2011-03-14 20:45:44

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> 

编辑:一般的根元素规则。

+0

+1。我会去同一个。 – Flack 2011-03-15 06:19:37

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

如果我的内部XSLT解析器是正确的,那么在您关闭标签之后会放上'',这不是他想要的。除此之外,这是一个非常好的解决方案。 – 2011-03-14 20:35:40

+0

@Bloodsplatter - 哎呀。你是对的。固定。 – 2011-03-14 20:36:49

+0

+1更多推式,但也是正确的。 – 2011-03-14 20:41:19

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> 

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. 身份规则将“按原样”复制每个节点。 ordersorderorder_line

  2. 身份规则由三个模板,其中的每一个匹配的特定种类的元素(顶部元件,Articleline)和简单地重命名元件,以分别覆盖。