XSLT dynamically filter on multiple elements

北城余情 提交于 2020-01-25 16:44:12

问题


I'm new to XSLT and trying to figure out how to use it to turn this XML:

<people>
    <person>
        <role>Parent</role>
        <lastname>Smith</lastname>
        <locations>
            <location>
                <city>Springfield</city>
                <state>MA</state>
                <unimportant-field>123</unimportant-field>
            </location>
            <location>
                <city>Chicago</city>
                <state>IL</state>
                <unimportant-field>456</unimportant-field>
            </location>
        </locations>
    </person>
    <person>
        <role>Child</role>
        <lastname>Smith</lastname>
        <locations>
            <location>
                <city>Springfield</city>
                <state>IL</state>
                <unimportant-field>789</unimportant-field>
            </location>
            <location>
                <city>Chicago</city>
                <state>IL</state>
                <unimportant-field>000</unimportant-field>
            </location>
            <location>
                <city>Washington</city>
                <state>DC</state>
                <unimportant-field>555</unimportant-field>
            </location>
        </locations>
    </person>
</people>

Into

<people>
    <person>
        <role>Parent</role>
        <lastname>Smith</lastname>
        <locations>
            <location>
                <city>Springfield</city>
                <state>MA</state>
                <unimportant-field>123</unimportant-field>
            </location>
            <location>
                <city>Chicago</city>
                <state>IL</state>
                <unimportant-field>456</unimportant-field>
            </location>
        </locations>
    </person>
    <person>
        <role>Child</role>
        <lastname>Smith</lastname>
        <locations>
            <location>
                <city>Chicago</city>
                <state>IL</state>
                <unimportant-field>000</unimportant-field>
            </location>
        </locations>
    </person>
</people>

Basically what is going on is that there is a pseudo hierarchy where I need to filter out locations on the "child" elements that don't also exist in the "parent" element. The child elements are related to their parent by lastname. However there is "unimportant-field" in each location that won't match between parent and child, but shouldn't affect the filtering.

Right now I'm trying to use this:

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

    <xsl:template match="/people">
        <people>
          <xsl:apply-templates select="person"/>
        </people>
    </xsl:template>

    <xsl:template match="person">
        <person>
            <xsl:copy-of select="role" /> 
            <xsl:copy-of select="lastname" /> 
            <xsl:apply-templates select="locations"/>
        </person>
    </xsl:template>

    <xsl:template match="locations">
        <locations>
            <xsl:apply-templates select="location[city = /people/person[role = 'Parent' and lastname = current()/../lastname]/locations/location/city and state = /people/person[role = 'Parent' and lastname = current()/../lastname]/locations/location/state]"/>
        </locations>
    </xsl:template>

    <xsl:template match="location">
        <location>
            <xsl:copy-of select="city" />
            <xsl:copy-of select="state" />
            <xsl:copy-of select="unimportant-field" />
        </location>
    </xsl:template>

</xsl:stylesheet>

The issue is that it is retaining the Springfield, IL element in the child because it is independently checking if the city exists anywhere in the parent and if the state exists anywhere in the parent. What I need to do is figure out if the combination of city and state exists on single location in the parent, while still ignoring "unimportant-field". I'm not sure how to do that though.


回答1:


Try it this way?

XSLT 1.0

<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:strip-space elements="*"/>

<xsl:key name="parent-location" match="person[role='Parent']/locations/location" use="concat(../../lastname, '|', city, '|', state)" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="person[role='Child']/locations/location[not(key('parent-location', concat(../../lastname, '|', city, '|', state)))]"/>

</xsl:stylesheet>


来源:https://stackoverflow.com/questions/25730940/xslt-dynamically-filter-on-multiple-elements

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!