比较2组子节点以查找匹配,其中至少一个子节点值与其他子节点值之一匹配

时间:2014-01-12 01:07:19

标签: xslt xpath xslt-1.0

我有两组表数据的XML(为简单起见,元素名称一般化)。

<root>
    <table>
        <Row type="1">
            <Id>AAAA</Id>
            <Properties>
                <Property>A</Property>
                <Property>D</Property>
            </Properties>
        </Row>
        <Row type="1">
            <Id>BBBB</Id>
            <Properties>
                <Property>B</Property>
            </Properties>
        </Row>
        <Row type="1">
            <Id>CCCC</Id>
            <Properties>
                <Property>G</Property>
                <Property>H</Property>
            </Properties>
        </Row>
    </table>
    <table>
        <Row type="2">
            <Id>123abc</Id>
            <Properties>
                <Property>A</Property>
                <Property>D</Property>
                <Property>E</Property>
            </Properties>
        </Row>
        <Row type="2">
            <Id>456def</Id>
            <Properties>
                <Property>B</Property>
                <Property>C</Property>
                <Property>I</Property>
            </Properties>
        </Row>
        <Row type="2">
            <Id>798ghi</Id>
            <Properties>
                <Property>F</Property>
                <Property>G</Property>
                <Property>H</Property>
            </Properties>
        </Row>
    </table>
</root>

我正在尝试编写一个转换来输出一个新表,该表根据表的属性将表1中的行与表2中的行相关联。表1中的行不要求表2中的所有属性都存在于行中;任何一个属性都需要被视为匹配。表1中的行与表2中的行之间始终只有一对一的关系。

我想要的输出是:

<root>
    <Row>
        <Name>NewTable:AAAA</Name>
        <Table2Id>123abc</Table2Id>
    </Row>
    <Row>
        <Name>NewTable:BBBB</Name>
        <Table2Id>456def</Table2Id>>
    </Row>
    <Row>
        <Name>NewTable:CCCC</Name>
        <Table2Id>789ghi</Table2Id>
    </Row>
</root>

我已经开始使用这个并且一直在尝试遵循这个逻辑:找到表2中行的Id标记,其中至少有一个属性与表1中正在处理的当前行的属性之一匹配

这是我到目前为止所拥有的。它不起作用,但我觉得我很接近。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

    <xsl:template match="//Row[@type != '2']">
            <xsl:variable name="Name" select="concat('NewTable:', ./Id)"/>
            <Row>
                <Name>
                    <xsl:value-of select="$Name"/>
                </Name>
                <Table2Id>
                    <xsl:value-of select="//Row[@type = '2'][Property = ./Property]/Id"/>
                </Table2Id>
            </Row>
    </xsl:template>

    <xsl:template match="/">
        <root>
            <xsl:apply-templates/>
        </root>
    </xsl:template>

    <xsl:template match="text()"/>

</xsl:stylesheet>    

1 个答案:

答案 0 :(得分:0)

这里有两件事非常有用:一件是XSLT的功能,它允许您根据匹配值创建关系。另一个是设置比较,如果集合中至少有一个成员与另一个集合中的至少一个成员匹配,则这些集合将被视为匹配。

尝试使用以下两种方式的样式表:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:key name="table2" match="Row[@type=2]" use="Properties/Property" />

<xsl:template match="/">
<root>
    <xsl:for-each select="root/table/Row[@type=1]">
    <row>   
        <Name>
            <xsl:value-of select="Id" />
        </Name>
        <Table2Id>
            <xsl:value-of select="key('table2', Properties/Property)/Id" />
        </Table2Id>
    </row>
    </xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>

顺便说一下,如果只使用过你的方法,你的方法也会有效(尽管效率较低):

[Properties/Property = ./Properties/Property]

而不只是:

[Property = ./Property]

因为您处于<Row><Property>的祖父母)的上下文中。