我一直在寻找,但未能找到我发现的任何想法。
这些是xml文件中的几个节点(从db生成)
<PANELS>
<PANEL ATTR1="7" ATTR2="37" ATTR3="31"/>
<PANEL ATTR1="8" ATTR2="37" ATTR3="31"/>
<PANEL ATTR1="8A" ATTR2="37" ATTR3="31"/>
</PANELS>
<ZONES>
<ZONE ATTR1="7" ATTR2="37" ATTR3="31" />
<ZONE ATTR1="8" ATTR2="37" ATTR3="31" />
<ZONE ATTR1="8A" ATTR2="37" ATTR3="31" />
</ZONES>
我希望能够从这些中选择不同的ATTR3。
目前,这适用于第一个
//PANELS/PANEL[not(@ATTR3 = (preceding::*/@ATTR3))]
并返回'31'的预期结果
但是当我尝试为第二个做同样的事情时,它什么都不返回(我希望它再次返回'31')
//ZONES/ZONE[not(@ATTR3 = (preceding::*/@ATTR3))]
我理解第二个不起作用,因为ATTR3的值对于所有这些都是相同的,但是如何获得每个节点的不同属性值?
(这被用作我用于显示每个不同值的for-each的谓词)
这是这样使用的,其中一个for-each
用于 ZONES ,一个用于 PANELS
<xsl:for-each select="//PANELS/PANEL[not(@ATTR3 = (preceding::*/@ATTR3))]">
<xsl:sort select="@ATTR3"/>
<xsl:value-of select="@ATTR3" />
<xsl:if test="position()!=last()">, </xsl:if>
</xsl:for-each>
我希望它返回
PANELS: 31
ZONES: 31
我尝试使用preceding-sibling
代替preceding
,但后来我
PANELS: 31, 31
ZONES: 31
每个人都在这样的模板中:
<xsl:template match="//HEADER/ZONES" >
<fo:block font-size="10pt">
<fo:table table-layout="fixed" >
<fo:table-column column-width="proportional-column-width(1)"/>
<fo:table-column column-width="proportional-column-width(7)"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell border-bottom="none">
<fo:block font-weight="bold">
<xsl:text>Zones:</xsl:text>
</fo:block>
</fo:table-cell >
<fo:table-cell>
<fo:block>
<xsl:for-each select="//HEADER/ZONES/ZONE[not(@ATTR3 = (preceding-sibling::*/@ATTR3))]">
<xsl:sort select="@ATTR3"/>
<xsl:value-of select="@ATTR3" />
<xsl:if test="position()!=last()">, </xsl:if>
</xsl:for-each>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
答案 0 :(得分:3)
以下XSLT使用preceding-siblings
而不是preceding
,从而生成 31 的正确重复次数:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="//HEADER/ZONES">
ZONES:
<xsl:for-each select="//ZONES/ZONE[not(@ATTR3 = (preceding-sibling::*/@ATTR3))]">
<xsl:sort select="@ATTR3"/>
<xsl:value-of select="@ATTR3" />
<xsl:if test="position()!=last()">, </xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="//HEADER/PANELS">
PANELS:
<xsl:for-each select="//PANELS/PANEL[not(@ATTR3 = (preceding-sibling::*/@ATTR3))]">
<xsl:sort select="@ATTR3"/>
<xsl:value-of select="@ATTR3" />
<xsl:if test="position()!=last()">, </xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
本文件的输出:
<HEADER>
<PANELS>
<PANEL ATTR1="7" ATTR2="37" ATTR3="31"/>
<PANEL ATTR1="8" ATTR2="37" ATTR3="31"/>
<PANEL ATTR1="8A" ATTR2="37" ATTR3="31"/>
</PANELS>
<ZONES>
<ZONE ATTR1="7" ATTR2="37" ATTR3="31" />
<ZONE ATTR1="8" ATTR2="37" ATTR3="31" />
<ZONE ATTR1="8A" ATTR2="37" ATTR3="31" />
</ZONES>
</HEADER>
如下:
ZONES:
31
PANELS:
31
答案 1 :(得分:1)
这个简短的(13行)和简单的转换 - 只有一个模板,没有硬编码的字符串:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:strip-space elements="*"/>
<xsl:template match="t/*[*/@ATTR3]">
<xsl:value-of select="concat(name(), ':')"/>
<xsl:for-each select="*/@ATTR3[not(. = ../preceding-sibling::*/@ATTR3)]">
<xsl:value-of select="concat(' ', .)"/>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML(包装成单个顶部元素以成为格式良好的)文档:
<t>
<PANELS>
<PANEL ATTR1="7" ATTR2="37" ATTR3="31"/>
<PANEL ATTR1="8" ATTR2="37" ATTR3="31"/>
<PANEL ATTR1="8A" ATTR2="37" ATTR3="31"/>
</PANELS>
<ZONES>
<ZONE ATTR1="7" ATTR2="37" ATTR3="31" />
<ZONE ATTR1="8" ATTR2="37" ATTR3="31" />
<ZONE ATTR1="8A" ATTR2="37" ATTR3="31" />
</ZONES>
</t>
会产生想要的正确结果:
PANELS: 31 ZONES: 31