xslt - XPath 1.0 选择 sibling 的不同属性

标签 xslt xpath-1.0

我四处寻找,但未能找到任何可行的想法。

这些是我在 xml 文件(从数据库生成)中的几个节点

<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 = (前面::*/@ATTR3))] 并返回“31”的预期结果

但是当我尝试对第二个执行相同操作时,它什么也没有返回(我希望它再次返回“31”) //ZONES/ZONE[not(@ATTR3 = (前面::*/@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>

最佳答案

以下 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

关于xslt - XPath 1.0 选择 sibling 的不同属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11363678/

相关文章:

python - 为什么 lxml 不允许在整个 ElementTree 上使用相对 XPath 表达式?

xml - 每个节点的最大不同子元素数

xml - XSLT 合并多个条目并将数字相加

c# - 如何在 C# 中启用 XSLT 脚本 ..?

date - XSLT 2.0 : Calculate age from DOB

selenium - 找不到正确的Xpath

xml - 使用 XPath 1.0 查找最小值不起作用

xslt - 使用XPath选择具有特定属性值的连续元素

xslt插入cdata