XSLT - 应用 muenchian 分组后计算子节点

XSLT - Counting child nodes after applying muenchian grouping

对于下面的输入 XML,我可以使用 muenchian grouping 方法将所有子 <invoice> 元素分组到适当的 <shippingBill> 元素下。但是,需要在最终输出 XML 中包含 <shippingBill> 个元素的 count 个元素和 <invoice> 个元素。我不知道该怎么做。

输入XML

<bank>
    <shippingBills>
        <shippingBill>
            <shippingBillNo>5786885</shippingBillNo>
            <shippingBillDate>10/02/2016</shippingBillDate>
            <LEODate>11/02/2016</LEODate>
            <invoice>
                <invoiceSerialNo>1</invoiceSerialNo>
                <invoiceNo>183</invoiceNo>
                <invoiceDate>07/02/2016</invoiceDate>
            </invoice>
        </shippingBill>
        <shippingBill>
            <shippingBillNo>5786885</shippingBillNo>
            <shippingBillDate>10/02/2016</shippingBillDate>
            <LEODate>11/02/2016</LEODate>
            <invoice>
                <invoiceSerialNo>2</invoiceSerialNo>
                <invoiceNo>184</invoiceNo>
                <invoiceDate>07/02/2016</invoiceDate>
            </invoice>
        </shippingBill>
        <shippingBill>
            <shippingBillNo>3318135</shippingBillNo>
            <shippingBillDate>01/10/2015</shippingBillDate>
            <LEODate>01/10/2015</LEODate>
            <invoice>
                <invoiceSerialNo>1</invoiceSerialNo>
                <invoiceNo>172</invoiceNo>
                <invoiceDate>29/09/2015</invoiceDate>
            </invoice>
        </shippingBill>
        <shippingBill>
            <shippingBillNo>3318135</shippingBillNo>
            <shippingBillDate>01/10/2015</shippingBillDate>
            <LEODate>01/10/2015</LEODate>
            <invoice>
                <invoiceSerialNo>2</invoiceSerialNo>
                <invoiceNo>173</invoiceNo>
                <invoiceDate>29/09/2015</invoiceDate>
            </invoice>
        </shippingBill>
    </shippingBills>
</bank>

XSL

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="key-bill" match="shippingBill" use="shippingBillNo"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" /> 
        </xsl:copy>
    </xsl:template>
    <xsl:template match="shippingBills">
        <xsl:copy>
            <xsl:apply-templates
                select="shippingBill[generate-id() = generate-id(key('key-bill', shippingBillNo)[1])]"
                mode="group" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="shippingBill" mode="group">
        <shippingBill>
            <xsl:apply-templates select="*[not(self::invoice)]" />
            <invoices>
                <xsl:apply-templates select="key('key-bill', shippingBillNo)/invoice" />
            </invoices>
        </shippingBill>
    </xsl:template>
</xsl:stylesheet>

最终输出XML需要

已添加 <checkSum> 元素,该元素具有保存相应计数的子元素。

<bank>
    <checkSum>
        <noOfInvoices>4</noOfInvoices>
        <noOfShippingBills>2</noOfShippingBills>
    </checkSum>
    <shippingBills>
        <shippingBill>
            <shippingBillNo>5786885</shippingBillNo>
            <shippingBillDate>10/02/2016</shippingBillDate>
            <LEODate>11/02/2016</LEODate>
            <invoices>
                <invoice>
                    <invoiceSerialNo>1</invoiceSerialNo>
                    <invoiceNo>183</invoiceNo>
                    <invoiceDate>07/02/2016</invoiceDate>
                </invoice>
                <invoice>
                    <invoiceSerialNo>2</invoiceSerialNo>
                    <invoiceNo>184</invoiceNo>
                    <invoiceDate>07/02/2016</invoiceDate>
                </invoice>
            </invoices>
        </shippingBill>
        <shippingBill>
            <shippingBillNo>3318135</shippingBillNo>
            <shippingBillDate>01/10/2015</shippingBillDate>
            <LEODate>01/10/2015</LEODate>
            <invoices>
                <invoice>
                    <invoiceSerialNo>1</invoiceSerialNo>
                    <invoiceNo>172</invoiceNo>
                    <invoiceDate>29/09/2015</invoiceDate>
                </invoice>
                <invoice>
                    <invoiceSerialNo>2</invoiceSerialNo>
                    <invoiceNo>173</invoiceNo>
                    <invoiceDate>29/09/2015</invoiceDate>
                </invoice>
            </invoices>
        </shippingBill>
    </shippingBills>
</bank>

我会这样做:

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="key-bill" match="shippingBill" use="shippingBillNo" />

    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="shippingBills">
        <xsl:variable name="distinct-bills" select="shippingBill[generate-id() = generate-id(key('key-bill', shippingBillNo)[1])]" />
        <checkSum>
            <noOfInvoices>
                <xsl:value-of select="count(shippingBill/invoice)" />
            </noOfInvoices>
            <noOfShippingBills>
                <xsl:value-of select="count($distinct-bills)" />
            </noOfShippingBills>
        </checkSum>
        <xsl:copy>
            <xsl:apply-templates select="$distinct-bills" mode="group" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="shippingBill" mode="group">
        <shippingBill>
            <xsl:apply-templates select="*[not(self::invoice)]" />
            <invoices>
                <xsl:apply-templates select="key('key-bill', shippingBillNo)/invoice" />
            </invoices>
        </shippingBill>
    </xsl:template>
</xsl:stylesheet>