XSLT foreach循环

问题描述:

我在过去的几周里只介绍过xslt和xml,我迫切需要一些帮助来编写一些代码来实现我想实现的目标。 我有以下XML:XSLT foreach循环

<?xml version="1.0" encoding="UTF-8"?> 
<abc1 formName="Form"> 
    <Level1> 
     <Element1>ZZZ</Element1> 
     <Element2> 
      <SubElement1>Apples</SubElement1> 
      <SubElement2>Oranges</SubElement2> 
      <SubElement3>Pears</SubElement3> 
      <SubElement4>Blueberries</SubElement4> 
      <SubElement5>Milkshakes</SubElement5> 
     </Element2> 
    </Level1> 
    <Level1> 
     <Element1>XXX</Element1> 
     <Element2> 
      <SubElement1>Apples</SubElement1> 
      <SubElement2>Oranges</SubElement2> 
      <SubElement3>Kiwifruit</SubElement3> 
      <SubElement4>Blueberries</SubElement4> 
      <SubElement5>Soda</SubElement5> 
     </Element2> 
    </Level1> 
</abc1> 

和下面的HTML表:

<table> 
<tr> 
    <td width="180" > Row 1</td> 
    <td width="540" colspan="4"> Cell_A</td> 
</tr> 
<tr> 
    <td width="180" >Types</td> 
    <td width="180" >Type 1</td> 
    <td width="180" >Type 2</td> 
    <td width="180" >Type 3</td> 
</tr> 
<tr> 
    <td width="180" >Row 2</td> 
    <td width="180" >Cell_B</td> 
    <td width="180" >Cell_C</td> 
    <td width="180" >Cell_D</td> 
</tr> 
<tr> 
    <td width="180" > Row 3</td> 
    <td width="180" >Cell_E</td> 
    <td width="180" >Cell_F</td> 
    <td width="180" >Cell_G</td> 
</tr> 
<tr> 
    <td width="180" >Row 4</td> 
    <td width="180" >Cell_H</td> 
    <td width="180" >Cell_I</td> 
    <td width="180" >Cell_J</td> 
</tr> 
<tr> 
    <td width="180" > Row 5</td> 
    <td width="540" colspan="4"> Cell_K</td> 
</tr> 
</table> 

我使用XSLT从XML数据提取到表,因为规则,我需要有麻烦申请使其非常复杂。以下是需要应用于我遇到麻烦的单元格的规则。

(1)如果<Element1>值是在整个XML,则相同的:

如果<Element1> = 'ZZZ' 然后Cell_B = '10',Cell_C = '20',和Cell_D = '30'

如果<Element1> = 'XXX' 然后Cell_B = '100',Cell_C = '90',和Cell_D = '80'

但如果<Element1>值不同在XML,则:

Cell_B = '10,100',Cell_C = '20,90'和Cell_D = '30,80'

(2)如果<SubElement5>值是在整个XML,则相同的:

Cell_J =的<SubElement5>

值,但如果<SubElement5>值在XML不同,则:

Cell_J =用逗号分隔的<SubElement5>值的值

所以在这种情况下,Cell_J的值将是'奶昔苏打'。

我一直在尝试用不同的东西:

<xsl:for-each select="./Level1/Element2"> 
<xsl:value-of select="./SubElement5"/> 
</xsl:for-each> 

,但我不能确定我可以使用什么样的代码来检查,如果它们是相同的,因为我不能覆盖变量的值。

编辑: 请注意,我在前面已经指出的小区(小区B,C,d,和j)是唯一我 需要帮助。另外,对于Element1,我可能遇到四个潜在值:012 ZXZ,XXX,AAA和BBB。所需的值对于每个这些将是: (小区B,C,和d)

ZZZ:10,20,30 
XXX:100,90,80 
AAA:40,30,30 
BBB:50,30,20 

所以如果只有一个在整个XML潜在价值,所述细胞应出现如上述的值。如果两个元素1的值不同,则单元格应在每个单元格中列出上述值,并用逗号分隔。

对于cell_j,我会尝试解释它好一点。

首先,我需要确定整个xml中<SubElement5>是否是相同的值。在这种情况下,它不是,在一个部分是奶昔,另一部分是'苏打'。因此,cell_J应该包含文字'奶昔,苏打'。

如果XML是这样的:

<?xml version="1.0" encoding="UTF-8"?> 
    <abc1 formName="Form"> 
     <Level1> 
      <Element1>ZZZ</Element1> 
      <Element2> 
       <SubElement1>Apples</SubElement1> 
       <SubElement2>Oranges</SubElement2> 
       <SubElement3>Pears</SubElement3> 
       <SubElement4>Blueberries</SubElement4> 
       <SubElement5>Milkshakes</SubElement5> 
      </Element2> 
     </Level1> 
     <Level1> 
      <Element1>XXX</Element1> 
      <Element2> 
       <SubElement1>Apples</SubElement1> 
       <SubElement2>Oranges</SubElement2> 
       <SubElement3>Kiwifruit</SubElement3> 
       <SubElement4>Blueberries</SubElement4> 
       <SubElement5>Milkshakes</SubElement5> 
      </Element2> 
     </Level1> 
    </abc1> 

那么对于cell_j值也只是 '奶昔'。

在此先感谢任何人谁可以提供帮助。

这个问题的答案:

总结一下伍迪下面没有为任何人的将来参考:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:template match="/abc1"> 
      <xsl:variable name="elements" select="//Element1[not(preceding::Element1 = .)]"/> 
<table> 
<tr> 
    <td width="180" > Row 1</td> 
    <td width="540" colspan="4"> Cell_A</td> 
</tr> 
<tr> 
    <td width="180" >Types</td> 
    <td width="180" >Type 1</td> 
    <td width="180" >Type 2</td> 
    <td width="180" >Type 3</td> 
</tr> 
<tr> 
    <td width="180" >Row 2</td> 
    <td width="180" > <xsl:for-each select="$elements"> 
      <xsl:if test="position() != 1">,</xsl:if> 
      <xsl:choose> 
       <xsl:when test=". = 'AAA'">40</xsl:when> 
       <xsl:when test=". = 'BBB'">50</xsl:when> 
       <xsl:when test=". = 'XXX'">100</xsl:when> 
       <xsl:when test=". = 'ZZZ'">10</xsl:when> 
      </xsl:choose> 
     </xsl:for-each></td> 
    <td width="180" ><xsl:for-each select="$elements"> 
      <xsl:if test="position() != 1">,</xsl:if> 
      <xsl:choose> 
       <xsl:when test=". = 'AAA'">30</xsl:when> 
       <xsl:when test=". = 'BBB'">30</xsl:when> 
       <xsl:when test=". = 'XXX'">90</xsl:when> 
       <xsl:when test=". = 'ZZZ'">20</xsl:when> 
      </xsl:choose> 
     </xsl:for-each></td> 
    <td width="180" ><xsl:for-each select="$elements"> 
      <xsl:if test="position() != 1">,</xsl:if> 
      <xsl:choose> 
       <xsl:when test=". = 'AAA'">30</xsl:when> 
       <xsl:when test=". = 'BBB'">20</xsl:when> 
       <xsl:when test=". = 'XXX'">80</xsl:when> 
       <xsl:when test=". = 'ZZZ'">30</xsl:when> 
      </xsl:choose> 
     </xsl:for-each></td> 
</tr> 
<tr> 
    <td width="180" > Row 3</td> 
    <td width="180" >Cell_E</td> 
    <td width="180" >Cell_F</td> 
    <td width="180" >Cell_G</td> 
</tr> 
<tr> 
    <td width="180" >Row 4</td> 
    <td width="180" >Cell_H</td> 
    <td width="180" >Cell_I</td> 
    <td width="180" ><xsl:for-each select="//SubElement5[not(preceding::SubElement5/text() = text())]"> 
     <xsl:if test="position() &gt; 1">, </xsl:if> 
     <xsl:value-of select="."/> 
    </xsl:for-each></td> 
</tr> 
<tr> 
    <td width="180" > Row 5</td> 
    <td width="540" colspan="4"> Cell_K</td> 
</tr> 
</table> 
     </xsl:template> 
    </xsl:stylesheet> 

伍迪,再次感谢,你。这真棒。

+0

您忘记指定进入单元格E,F,G,H和I的内容。请*编辑*问题并提供缺少的信息。 –

与您问题的关键是,你无法通过数据itterate得到你想要的东西,因为你想要的答案是固定的,即如果此,输出的是,如果这等输出。因此,您需要一次完成每个部分。

是否有永远只能2 Level1s?

 <xsl:template match="/abc1"> 
      <table> 
       <tr> 
        <td width="180" >Row 2</td> 
      <xsl:choose> 
       <xsl:when test="not(Level1/Element1='XXX')"> 
        <!-- only ZZZ --> 
         <td width="180" >10</td> 
         <td width="180" >20</td> 
         <td width="180" >30</td> 
       </xsl:when> 
       <xsl:when test="not(Level1/Element1='ZZZ')"> 
        <!-- only YYY --> 
         <td width="180" >100</td> 
         <td width="180" >90</td> 
         <td width="180" >80</td> 
       </xsl:when> 
       <xsl:otherwise> 
        <!-- some combination --> 
         <td width="180" >10,100</td> 
         <td width="180" >20,90</td> 
         <td width="180" >30,80</td> 
       </xsl:otherwise> 
       </xsl:choose> 
       </tr> 
       .. continued 
      </table> 
     </xsl:template> 
    </xsl:stylesheet> 

等每部分。如果你有一个行数,你想他们,那么逗号分隔,你需要做的每节 或者如果你必须把一个逗号列表中每个部分。

对不起,我看不出有什么你试图用cell_j做,似乎没有成为其他的人

修改规则:但是,如果你有很多的项目,而不仅仅是2,你需要一个逗号分隔的列表,你可以使用XPath做,所以:再次

<tr> 
    <td> 
    <xsl:for-each select="//SubElement5[not(preceding::SubElement5/text() = text())]"> 
     <xsl:if test="position() &gt; 1">, </xsl:if> 
     <xsl:value-of select="."/> 
    </xsl:for-each> 
    </td> 
    .. maybe other rows the same 
</tr> 

编辑:

所以有关cell_j更新的问题,上面用正确的来了值。

对于第一部分的更新,这将是可能做到对同一主题的变化,如果你想显示的所有值(所以有4个值,如果你有所有的4个选项)。不幸的是,你已经订好每一个值,你必须通过一个一个做各,你需要做一个大的部分,所以在一个循环:

<xsl:for-each select="//Element1[not(preceding::Element1/text() = text())]"> 

这将使你在为一个循环每个唯一的条目,然后根据该值是否为XXX,ZZZ等来选择元素

再次编辑

有做你想做的第一部分,包括递归函数,外部文档,并使用各种不同的XSLT implimentations的节点集函数的几种方式,但作为一个完全通用容易看不到出路,这是稍微罗嗦,但是很容易看到的版本(我希望):

<xsl:variable name="elements" select="//Element1[not(preceding::Element1 = .)]"/> 
<table> 
    <tr> 
     <td width="180" >Row 2</td> 
    <td> 
     <xsl:for-each select="$elements"> 
      <xsl:if test="position() != 1">,</xsl:if> 
      <xsl:choose> 
       <xsl:when test=". = 'AAA'">40</xsl:when> 
       <xsl:when test=". = 'BBB'">50</xsl:when> 
       <xsl:when test=". = 'XXX'">100</xsl:when> 
       <xsl:when test=". = 'ZZZ'">10</xsl:when> 
      </xsl:choose> 
     </xsl:for-each> 
    </td> 
    <td> 
     <xsl:for-each select="$elements"> 
      <xsl:if test="position() != 1">,</xsl:if> 
      <xsl:choose> 
       <xsl:when test=". = 'AAA'">30</xsl:when> 
       <xsl:when test=". = 'BBB'">30</xsl:when> 
       <xsl:when test=". = 'XXX'">90</xsl:when> 
       <xsl:when test=". = 'ZZZ'">20</xsl:when> 
      </xsl:choose> 
     </xsl:for-each> 
    </td> 
    <td> 
     <xsl:for-each select="$elements"> 
      <xsl:if test="position() != 1">,</xsl:if> 
      <xsl:choose> 
       <xsl:when test=". = 'AAA'">30</xsl:when> 
       <xsl:when test=". = 'BBB'">20</xsl:when> 
       <xsl:when test=". = 'XXX'">80</xsl:when> 
       <xsl:when test=". = 'ZZZ'">30</xsl:when> 
      </xsl:choose> 
     </xsl:for-each> 
    </td> 
    </tr> 
</table> 

其实 - 我不知道,如果一个变量的迭代($在这种情况下,元素)是标准的,它可能是一个撒克逊和msxsl的事情,但如果不是,你可以用它的值替换它(// Element1 [not(preceding :: Element1 =。)])

+0

感谢您的帮助。要回答你的问题,我会在我原来的帖子中添加一些额外的信息。 –

+0

再次感谢您。你可以用例子展开最后一节>我不太清楚你的意思。 –

+0

我的意思是,因为一旦你确定了你有哪些独特的元素,你必须把它们放在每个​​中,你必须做3次测试,每次td一次,因为没有办法存储这个值,为了打印价值观而着手。所以,即使你做了一个测试,发现ZZZ是存在的,并且你知道所有tds的所有3个值,你必须在开始第二个td之前完成第一个td。我现在还没有机会写下来,如果你仍然需要,可以在几个小时内完成。 – Woody