我在过去几周才被介绍给xslt和xml,我迫切需要一些帮助来编写一些代码来实现我想要实现的目标。 我有以下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>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)如果整个xml中<Element1>
值相同,则:
如果<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)如果整个xml中<SubElement5>
值相同,则:
Cell_J = <SubElement5>
但如果<SubElement5>
值在xml中不同,则:
Cell_J =以逗号分隔的两个<SubElement5>
值的值
所以在这种情况下,Cell_J的值将是'Milkshakes,Soda'。
我一直在尝试使用不同的东西:
<xsl:for-each select="./Level1/Element2">
<xsl:value-of select="./SubElement5"/>
</xsl:for-each>
但是我无法确定我可以使用哪些代码来检查它们是否相同,因为我无法覆盖变量的值。
修改
请注意,我上面指出的细胞(细胞b,c,d和j)是我唯一的细胞
需要帮助。此外,对于Element1
,我可以有四个潜在的值
遭遇:ZZZ,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应包含文本'Milkshakes,Soda'。
如果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的值就是'Milkshakes'。
提前感谢任何可以提供帮助的人。
回答这个问题:
总结伍迪在下面所做的事情,以供将来参考:
<?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() > 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 :(得分:2)
你的问题的关键在于你无法通过数据来获得你想要的东西,因为你想要的答案是固定的,即,如果这样,输出那个,如果那样,输出另一个。所以你需要一次拍摄每个部分。
是否只有两个Level1?
<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() > 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实现的节点集函数,但作为一个完全通用的易于查看的方式,这是有点罗嗦,但很容易看到版本(我希望):
<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>
实际上 - 我不确定迭代变量(在这种情况下是$元素)是否是标准,它可能是saxon和msxsl的东西,但如果不是,你可以用值替换它( // Element1 [not(preceding :: Element1 =。)])