XSL复杂选择条件

时间:2016-02-21 21:15:49

标签: xslt xslt-1.0

我有一个XML结构,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Customers>
    <Customer UD="XYZ">
        <Info>
                ...
            </Info>
            <Travel>
                <Trip Country="US" Year="2013" LengthOfStay="P13D"/>
                <Trip Country="IT" Year="2015" LengthOfStay="P9D"/>
                <Trip Country="JP" Year="2015" LengthOfStay="P5D"/>
            </Travel>
        </Customer>
        <Customer UD="ABC">
            ...
        </Customer>
</Customers>

我想创建一个复杂的选择条件,以返回过去X年每年旅行次数超过X次的客户。

有可能吗?非常感谢!

2 个答案:

答案 0 :(得分:1)

我认为可以直接选择合格客户,但您可以使用递归模板处理客户并仅在他们通过时输出结果测试

以下是一个例子:

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="trip" match="Trip" use="concat(@Year, '|', ../../@UD)" />

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

<xsl:template match="Customer">
    <xsl:call-template name="test-years"/>
</xsl:template>

<xsl:template name="test-years">
    <xsl:param name="year" select="2016"/>
    <xsl:param name="years-to-test" select="3"/>
    <xsl:param name="min-trips" select="3"/>
    <xsl:variable name="n" select="count(key('trip', concat($year, '|', @UD)))" />
    <xsl:choose>
        <xsl:when test="$n &lt; $min-trips">
            <!-- exit with no result -->
        </xsl:when>
        <xsl:when test="$years-to-test > 1">
            <!-- recursive call -->
            <xsl:call-template name="test-years">
                <xsl:with-param name="year" select="$year - 1"/>
                <xsl:with-param name="years-to-test" select="$years-to-test - 1"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <!-- test passed: output the result -->
            <xsl:copy-of select="."/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

注意:XSLT 1.0没有当前年份的概念 - 您必须使用扩展功能(取决于您的特定处理器支持的功能),或者在运行时将当前日期作为参数传递给样式表。

答案 1 :(得分:1)

我的逻辑中可能有一个缺陷,但尝试这个XSLT

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

    <xsl:param name="firstYear" select="2012" />
    <xsl:param name="lastYear" select="2015" />
    <xsl:param name="times" select="2" />

    <xsl:variable name="Years" select="$lastYear - $firstYear + 1" />

    <xsl:key name="Trip" match="Trip" use="concat(@Year, '|', ../../@UD)" />

    <xsl:template match="Customers">
        <xsl:copy>
            <xsl:apply-templates select="Customer[count(.//Trip
                               [@Year >= $firstYear and @Year &lt;= $lastYear]
                               [generate-id() = generate-id(key('Trip', concat(@Year, '|', ../../@UD))[1])]
                               [count(key('Trip', concat(@Year, '|', ../../@UD))) >= $times]
                            ) = $Years]" />
        </xsl:copy>
    </xsl:template>

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

对于每个客户,这可以获得一年范围内不同旅行的次数(例如,对于三年范围,您需要三年不同,否则这意味着他们不会每年旅行)和每个不同的年份,它计算一年中旅行的次数,以满足要求。如果此类行程的总数等于所需的年数,则可以输出客户。