Subject: Re: [xsl] How to remove double elements????? From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx> Date: Thu, 16 May 2002 18:44:33 +0100 |
Hi Stephan, > 1.) > Is there an elegant possibility to remove double elements??? By > using my version the first element gets lost!! The reason that your first element gets lost is that you're testing: preceding-sibling::computer[1]/@name != @name which asks whether there's an immediately preceding computer element whose name attribute isn't the same as the name attribute on this computer element. This isn't true for the first computer, because it doesn't have a preceding sibling. Use: not(preceding-sibling::computer[1]/@name = @name) instead; this asks whether there isn't a preceding sibling computer element with the same name as this one. > 2.) > Is it possible to get these functionaltities with LESS code > (especially with LESS variables)?????? Yes, I think so. Let me make sure I understand what you're doing first, though. Each tool has a name and version, matching a release in $sw-file. Each release has several computers, each of which has a name matching a computer in $hw-file. You want to get a copy of the computers from the $hw-file that are named by any of the computers under the releases in the $sw-file that are identified by the set of tools you're looking at. Can I assume that in the $hw-file, there's only one computer element with a particular version and name? If so, I think it would be simpler if you turned it around, so that you actually went through the computers within the $hw-file, sorted by their function and name: <xsl:for-each select="computer"> <xsl:sort select="@version" /> <xsl:sort select="@number" /> <xsl:variable name="computer" select="." /> ... </xsl:for-each> For each of them, look in the $sw-file to find out if there are any releases that contain computers with that name. Set up a key like: <xsl:key name="releases" match="release" use="computer/@name" /> and then do: <xsl:for-each select="computer"> <xsl:sort select="@version" /> <xsl:sort select="@number" /> <xsl:variable name="computer" select="." /> <xsl:for-each select="$sw-file"> <xsl:variable name="releases" select="key('releases', $computer/@name)" /> ... </xsl:for-each> </xsl:for-each> Then you need to find out whether there are any tools that share (I guess) the same name and version as the release. So have a key like: <xsl:key name="tools" match="tool" use="concat(@name, '#', @version)" /> I'll assume that the tools are listed in the $hw-file. Create a variable by going through each of the releases in turn and try to find a tool with the same name and version. If you find one, add some text to the variable (it doesn't matter what the text is -- it just acts as a flag so that we can tell that a release has been identified): <xsl:for-each select="computer"> <xsl:sort select="@version" /> <xsl:sort select="@number" /> <xsl:variable name="computer" select="." /> <xsl:for-each select="$sw-file"> <xsl:variable name="releases" select="key('releases', $computer/@name)" /> <xsl:variable name="createCopy"> <xsl:for-each select="$releases"> <xsl:variable name="releaseKey" select="concat(@name, '#', @version)" /> <xsl:for-each select="$hw-file"> <xsl:if test="key('tools', $releaseKey)"> Yes, there's a release for this computer </xsl:if> </xsl:for-each> </xsl:for-each> </xsl:variable> ... </xsl:for-each> </xsl:for-each> Then if the $createCopy variable has a string value, you know that you should create a copy of the particular computer. Just do: <xsl:for-each select="computer"> <xsl:sort select="@version" /> <xsl:sort select="@number" /> <xsl:variable name="computer" select="." /> <xsl:for-each select="$sw-file"> <xsl:variable name="releases" select="key('releases', $computer/@name)" /> <xsl:variable name="createCopy"> <xsl:for-each select="$releases"> <xsl:variable name="releaseKey" select="concat(@name, '#', @version)" /> <xsl:for-each select="$hw-file"> <xsl:if test="key('tools', $releaseKey)"> Yes, there's a release for this computer </xsl:if> </xsl:for-each> </xsl:for-each> </xsl:variable> <xsl:if test="string($createCopy)"> <xsl:copy-of select="$computer" /> </xsl:if> </xsl:for-each> </xsl:for-each> No result tree fragment variables at all. --- In XSLT 2.0, thanks primarily to general steps and the ability to construct sequences of values, we'll be able to do this really easily: <xsl:variable name="toolkeys" select="for $tool in tool return concat(@name, '#', @version)" /> <xsl:variable name="computerNames" select="$sw-file/key('releasekey', $toolkeys)/computer/@name" /> <xsl:for-each select="$hw-file/key('hw_key', $computerNames)"> <xsl:sort select="@version" /> <xsl:sort select="@name" /> <xsl:copy-of select="." /> </xsl:for-each> If (as looks likely) XPath 2.0 keeps its current for expressions, you could alternatively create a named sort specification: <xsl:sort-key name="computers"> <xsl:sort select="@version" /> <xsl:sort select="@name" /> </xsl:sort-key> and then tuck it all up inside a single XPath and take an XQuery-like approach instead: <xsl:copy-of select=" sort('computers', for $tool in tool, $release in $sw-file/key('releasekey', concat($tool/@name, '#', $tool/@version)), $computer in $hw-file/key('hw_key', $release/computer/@name) return $computer)" /> 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 -> |
---|---|---|
[xsl] How to remove double elements, ChivaBaba | Thread | [xsl] Empty textarea tag in stylesh, Charles Knell |
Re: [xsl] Simple problem - complica, Joerg Heinicke | Date | RE: [xsl] flattening nested xml, Stuart Celarier |
Month |