Subject: Re: [xsl] cross document id idref pair checks From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx> Date: Tue, 9 Jan 2001 18:34:52 +0000 |
David Carlisle wrote: > Dave Pawson wrote: >> When using well formed, as apposed to valid, input, How to use the >> fact that a node-set removes duplicates to check if there is more >> than one attribute named 'id'? > > If it has duplicated attributes, it's not well formed. I think (?) that DaveP meant duplicated values for @id attributes across a document rather than duplicate @id attributes on a particular element. If there is an element that has the same @id attribute as the current element, then: @id = (preceding::*/@id | following::*/@id) would be true. You can get elements that have repeated ids with: //*[@id = (preceding::*/@id | following::*/@id)] Of course if you test the above expression as a boolean, then it will return true if there are any repeated ids in the document. You can list the IDs that are repeated (once per ID) with: //*[not(preceding::*/@id = @id) and following::*/@id = @id] The preceding:: and following:: axes are, of course, horribly inefficient. You could use a recursive solution instead, or you could use keys: <xsl:key name="ids" select="*" use="@id" /> If, for an element, the 'ids' key returns more than one node, then it's a repeated id, so you can test whether there are any repeats with: //*[key('ids', @id)[2]] [Aside: I've started using positional predicates to test whether a node set has more than a certain number of nodes, although perhaps any processor that optimises '$nodes[2]' will also optimise 'count($nodes) > 1'. Any thoughts?] If you want to get a list (without repeats) of the repeated IDs using the key() method, then you can use the usual: //*[key('ids', @id)[2] and count(.|key('ids', @id)[1]) = 1] [or actually, by extension to the above aside: //*[key('ids', @id)[2] and not((.|key('ids', @id)[1])[2])] making identity-testing of nodes even more obscure! :)] Testing this across documents is harder because (a) nodes from different documents aren't related to each other through axes and (b) key() is scoped within the document of the context node. Probably the simplest solution is to create a node set variable holding copies of the nodes from the relevant documents, and then test that as if it were a document on its own: <xsl:variable name="IDed-elements"> <xsl:copy-of select="(/ | document('foo.xml'))//*[@id]" /> </xsl:variable> <xsl:if test="$IDed-elements//*[key('ids', @id)[2]]"> <!-- repeated IDs --> </xsl:if> Alternatively, you could use a recursive method. Cheers, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] cross document id idref p, David Carlisle | Thread | Re: [xsl] cross document id idref p, David Carlisle |
Re: [xsl] Usefull?, David Carlisle | Date | Re[2]: Possible new key () function, Steven . C . Kienle |
Month |