Selecting unique records in XSLT/XPath

后端 未结 2 1781
陌清茗
陌清茗 2021-01-13 06:42

I have to select only unique records from an XML document, in the context of an loop. I am limited by Visual Studio to usi

相关标签:
2条回答
  • 2021-01-13 07:04

    I. As a single XPath expression:

    /*/item[normalize-space() and not(. = preceding-sibling::item)]
    

    II. More efficient (XSLT) implementation, using keys:

    <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="kItemByVal" match="item" use="."/>
    
     <xsl:template match="/">
      <xsl:copy-of select=
       "*/item[generate-id() = generate-id(key('kItemByVal', .))]
       "/>
     </xsl:template>
    </xsl:stylesheet>
    

    Both I and II, when applied on the provided XML document correctly select/copy the following nodes:

    <item><schDate>2010-06-24</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>13:00:00</schToTime></item>
    <item><schDate>2010-06-25</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>12:00:00</schToTime></item>
    <item><schDate>2010-06-26</schDate><schFrmTime>13:00:00</schFrmTime><schToTime>14:00:00</schToTime></item>
    <item><schDate>2010-06-26</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>12:00:00</schToTime></item>
    

    Update: In case <item> has other children, then this transformation:

    <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
        <xsl:key name="kItemBy3Children" match="item"
         use="concat(schDate, '+', schFrmTime, '+', schToTime)"/>
    
     <xsl:template match="/">
           <xsl:copy-of select=
            "*/item[generate-id()
                  = generate-id(key('kItemBy3Children',
                                    concat(schDate,
                                           '+', schFrmTime,
                                           '+', schToTime)
                                   )
                                )
                   ]
            "/>
     </xsl:template>
    </xsl:stylesheet>
    

    produces the wanted result.

    0 讨论(0)
  • 2021-01-13 07:21

    The technique I've seen is to do this in two passes: sort the items by all three key fields, and then compare each item to its preceding item (instead of all preceding items).

    Is it practical for you to run two separate transformations? It makes the problem much easier.

    I saw the technique in an older edition of Michael Kay's XSLT book. You might find it in some of his sample code there.

    0 讨论(0)
提交回复
热议问题