XSLT从多个重复出现的重复标头中选择特定的子元素

时间:2017-03-22 18:11:28

标签: xml xslt soap

我通常可以找到我问的问题的答案,但这个问题真的让我很难过。我有一个XSLT和一个输入XML文档,我需要从父元素中提取日期时间,这些元素都是模仿彼此的。我如何格式化,它在80%的时间内工作,但另外20%的时间它会混乱并发送错误的时间,因为使用的是同一个单元的多个相同状态。 ALL字段是可变的,但设置了单位状态。 (参见XSLT)。

问题:稍后时间会覆盖文件提交的早期时间。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <soap:Envelope xsl:version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
            <ApparatusEvents>
                <xsl:for-each select="/ICADLINK_EVENT/UN_HI_LIST/UN_HI">
                    <xsl:if test="UNIT_STATUS = 'DP' and DGROUP = 'SNR'">
                        <ApparatusEvent>
                            <Apparatus>
                                <xsl:value-of select="UNID"/>
                            </Apparatus>
                            <Type>Dispatch</Type>
                            <DateTime>
                                <xsl:value-of select="CDTS_TIMESTAMP/CDTS_DATETIME"/>
                            </DateTime>
                            <UnitCancelledFlag>false</UnitCancelledFlag>
                        </ApparatusEvent>
                    </xsl:if>
                </xsl:for-each>
            </ApparatusEvents>
            <ApparatusEvents>
                <xsl:for-each select="/ICADLINK_EVENT/UN_HI_LIST/UN_HI">
                    <xsl:if test="UNIT_STATUS = 'ER' and DGROUP = 'SNR'">
                        <ApparatusEvent>
                            <Apparatus>
                                <xsl:value-of select="UNID"/>
                            </Apparatus>
                            <Type>Enroute</Type>
                            <DateTime>
                                <xsl:value-of select="CDTS_TIMESTAMP/CDTS_DATETIME"/>
                            </DateTime>
                            <UnitCancelledFlag>false</UnitCancelledFlag>
                        </ApparatusEvent>
                    </xsl:if>
                </xsl:for-each>
            </ApparatusEvents>
            <ApparatusEvents>
                <xsl:for-each select="/ICADLINK_EVENT/UN_HI_LIST/UN_HI">
                    <xsl:if test="UNIT_STATUS = 'AR' and DGROUP = 'SNR'">
                        <ApparatusEvent>
                            <Apparatus>
                                <xsl:value-of select="UNID"/>
                            </Apparatus>
                            <Type>Arrived</Type>
                            <DateTime>
                                <xsl:value-of select="CDTS_TIMESTAMP/CDTS_DATETIME"/>
                            </DateTime>
                            <UnitCancelledFlag>false</UnitCancelledFlag>
                        </ApparatusEvent>
                    </xsl:if>
                </xsl:for-each>
            </ApparatusEvents>
        </soap:Body>
    </soap:Envelope>
</xsl:template>

编辑输入文件:

<?xml version="1.0" encoding="ISO-8859-1"?>
<ICADLINK_EVENT version="1.0" creationdate="3/29/2016 8:34:57 AM">
<UN_HI_LIST>
<UN_HI>
    <CDTS_TIMESTAMP>
        <CDTS_DATE>3/29/2016</CDTS_DATE>
        <CDTS_TIME>08:12:54</CDTS_TIME>
        <CDTS_DATETIME>3/29/2016 08:12:54</CDTS_DATETIME>
    </CDTS_TIMESTAMP>
    <UNID>E7</UNID>
    <UNIT_STATUS>DP</UNIT_STATUS>
    <DGROUP>SNR</DGROUP>
</UN_HI>
<UN_HI>
    <CDTS_TIMESTAMP>
        <CDTS_DATE>3/29/2016</CDTS_DATE>
        <CDTS_TIME>08:13:54</CDTS_TIME>
        <CDTS_DATETIME>3/29/2016 08:13:54</CDTS_DATETIME>
    </CDTS_TIMESTAMP>
    <UNID>E7</UNID>
    <UNIT_STATUS>ER</UNIT_STATUS>
    <DGROUP>SNR</DGROUP>
</UN_HI>
<UN_HI>
    <CDTS_TIMESTAMP>
        <CDTS_DATE>3/29/2016</CDTS_DATE>
        <CDTS_TIME>08:15:05</CDTS_TIME>
        <CDTS_DATETIME>3/29/2016 08:15:05</CDTS_DATETIME>
    </CDTS_TIMESTAMP>
    <UNID>E607</UNID>
    <UNIT_STATUS>DP</UNIT_STATUS>
    <DGROUP>SNR</DGROUP>
</UN_HI>
<UN_HI>
    <CDTS_TIMESTAMP>
        <CDTS_DATE>3/29/2016</CDTS_DATE>
        <CDTS_TIME>08:15:05</CDTS_TIME>
        <CDTS_DATETIME>3/29/2016 08:15:05</CDTS_DATETIME>
    </CDTS_TIMESTAMP>
    <UNID>E607</UNID>
    <UNIT_STATUS>ER</UNIT_STATUS>
    <DGROUP>SNR</DGROUP>
</UN_HI>
<UN_HI>
    <CDTS_TIMESTAMP>
        <CDTS_DATE>3/29/2016</CDTS_DATE>
        <CDTS_TIME>08:20:39</CDTS_TIME>
        <CDTS_DATETIME>3/29/2016 08:20:39</CDTS_DATETIME>
    </CDTS_TIMESTAMP>
    <UNID>E607</UNID>
    <UNIT_STATUS>AR</UNIT_STATUS>
    <DGROUP>SNR</DGROUP>
</UN_HI>
<UN_HI>
    <CDTS_TIMESTAMP>
        <CDTS_DATE>3/29/2016</CDTS_DATE>
        <CDTS_TIME>08:21:19</CDTS_TIME>
        <CDTS_DATETIME>3/29/2016 08:21:19</CDTS_DATETIME>
    </CDTS_TIMESTAMP>
    <UNID>E7</UNID>
    <UNIT_STATUS>AR</UNIT_STATUS>
    <DGROUP>SNR</DGROUP>
</UN_HI>
<UN_HI>
    <CDTS_TIMESTAMP>
        <CDTS_DATE>3/29/2016</CDTS_DATE>
        <CDTS_TIME>08:21:46</CDTS_TIME>
        <CDTS_DATETIME>3/29/2016 08:21:46</CDTS_DATETIME>
    </CDTS_TIMESTAMP>
    <UNID>E607</UNID>
    <UNIT_STATUS>AR</UNIT_STATUS>
    <DGROUP>SNR</DGROUP>
</UN_HI>

当前输出:(它将E607单元的Arrived节点发送两次,在这种情况下,它会在数据库中覆盖并占用最新时间,因为它是最新更新的文件。)

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
    <ApparatusEvents>
        <ApparatusEvent>
            <Apparatus>E7</Apparatus>
            <Type>Dispatch</Type>
            <DateTime>3/29/2016 08:12:54</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
        <ApparatusEvent>
            <Apparatus>E607</Apparatus>
            <Type>Dispatch</Type>
            <DateTime>3/29/2016 08:15:05</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
    </ApparatusEvents>
    <ApparatusEvents>
        <ApparatusEvent>
            <Apparatus>E7</Apparatus>
            <Type>Enroute</Type>
            <DateTime>3/29/2016 08:13:54</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
        <ApparatusEvent>
            <Apparatus>E607</Apparatus>
            <Type>Enroute</Type>
            <DateTime>3/29/2016 08:15:05</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
    </ApparatusEvents>
    <ApparatusEvents>
        <ApparatusEvent>
            <Apparatus>E607</Apparatus>
            <Type>Arrived</Type>
            <DateTime>**3/29/2016 08:20:39**</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
        <ApparatusEvent>
            <Apparatus>E7</Apparatus>
            <Type>Arrived</Type>
            <DateTime>3/29/2016 08:21:19</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
        <ApparatusEvent>
            <Apparatus>E607</Apparatus>
            <Type>Arrived</Type>
            <DateTime>**3/29/2016 08:21:46**</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
    </ApparatusEvents>
    <ApparatusEvents/>
    <ApparatusEvents/>
    <ApparatusEvents/>
    <ApparatusEvents/>
    <ApparatusEvents/>
    <ApparatusEvents/>
</soap:Body>

所需输出:(我需要它才能获取SAME单元​​的多个状态的早期或更晚时间)

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
    <ApparatusEvents>
        <ApparatusEvent>
            <Apparatus>E7</Apparatus>
            <Type>Dispatch</Type>
            <DateTime>3/29/2016 08:12:54</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
        <ApparatusEvent>
            <Apparatus>E607</Apparatus>
            <Type>Dispatch</Type>
            <DateTime>3/29/2016 08:15:05</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
    </ApparatusEvents>
    <ApparatusEvents>
        <ApparatusEvent>
            <Apparatus>E7</Apparatus>
            <Type>Enroute</Type>
            <DateTime>3/29/2016 08:13:54</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
        <ApparatusEvent>
            <Apparatus>E607</Apparatus>
            <Type>Enroute</Type>
            <DateTime>3/29/2016 08:15:05</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
    </ApparatusEvents>
    <ApparatusEvents>
        **<ApparatusEvent>
            <Apparatus>E607</Apparatus>
            <Type>Arrived</Type>
            <DateTime>3/29/2016 08:20:39</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>**
        <ApparatusEvent>
            <Apparatus>E7</Apparatus>
            <Type>Arrived</Type>
            <DateTime>3/29/2016 08:21:19</DateTime>
            <UnitCancelledFlag>false</UnitCancelledFlag>
        </ApparatusEvent>
    </ApparatusEvents>
    <ApparatusEvents/>
    <ApparatusEvents/>
    <ApparatusEvents/>
    <ApparatusEvents/>
    <ApparatusEvents/>
    <ApparatusEvents/>
</soap:Body>

1 个答案:

答案 0 :(得分:0)

为了最大限度地减少这个例子,让我们专注于只生成你的第三个ApparatusEvents分支。正如我在评论中提到的,这是一个典型的Muenchian分组问题,有两个复杂问题。

第一个复杂因素是你只想考虑一些 UN_HI元素 - 所以你需要定义一个只匹配这些节点的键(你必须定义其他键)其他ApparatusEvents分支),并在调用此密钥时重复相同的谓词:

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:key name="key3" match="UN_HI[UNIT_STATUS='AR' and DGROUP='SNR']" use="UNID" />

<xsl:template match="/">
    <soap:Envelope xsl:version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
            <!-- skipped -->
            <ApparatusEvents>
                <xsl:variable name="records" select="/ICADLINK_EVENT/UN_HI_LIST/UN_HI[UNIT_STATUS='AR' and DGROUP='SNR']"/>
                <!-- for each distinct group -->
                <xsl:for-each select="$records[count(. | key('key3', UNID)[1]) = 1]">
                    <!-- get the earliest record in this group -->
                        <xsl:for-each select="key('key3', UNID)">
                            <xsl:sort select="CDTS_TIMESTAMP/CDTS_DATETIME" data-type="text" order="ascending"/>
                            <xsl:if test="position()=1">
                                <ApparatusEvent>
                                    <Apparatus>
                                        <xsl:value-of select="UNID"/>
                                    </Apparatus>
                                    <Type>Arrived</Type>
                                    <DateTime>
                                        <xsl:value-of select="CDTS_TIMESTAMP/CDTS_DATETIME"/>
                                    </DateTime>
                                    <UnitCancelledFlag>false</UnitCancelledFlag>
                                </ApparatusEvent>
                            </xsl:if>
                        </xsl:for-each>
                </xsl:for-each>
            </ApparatusEvents>
        </soap:Body>
    </soap:Envelope>
</xsl:template>

</xsl:stylesheet>

第二个复杂因素是按CDTS_DATETIME排序不会产生按时间顺序排列,因为格式不是YYYY-MM-DD。这与这里的主要问题无关,所以我不打算讨论它。您可以在此处查看如何处理此问题的示例:Tokenize and compare dates in xslt 1.0