[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Removing duplicates for unknown number of elements
Hi Chris, > 1. The first problem I have is that (from the XML input) you can see > that after WS/CONTENT/ROWS/ROW, the nodes beneath that change .. is > this bad XML design? Well, you might want to think about using namespaces to divide the stuff that's about the layout from the stuff that's about the content. So you could have: <ROW> <sport:NAME>Shaq O'Neal</sport:NAME> <sport:EMAIL>shaq@xxxxxxxxxx</sport:EMAIL> </ROW> ... <ROW> <sport:SPORT>Basketball</sport:SPORT> <sport:TEAM>Lakers</sport:TEAM> <sport:CITY>Los Angeles</sport:CITY> </ROW> It's not clear to me what the CONTENT, ROWS and ROW elements mean particularly. For example, why don't you have something that's purely about the information that you want to hold, like: <SPORT>Basketball</SPORT> <TEAM>Lakers</TEAM> <CITY>Los Angeles</CITY> <PLAYERS> <PLAYER> <NAME>Shaq O'Neal</NAME> <EMAIL>shaq@xxxxxxxxxx</EMAIL> </PLAYER> ... </PLAYERS> > 2. Most of the stuff above works... it's just *bad-looking*... i got > node() calls hooked up which don't look very nice... Yes, many of your paths look very strange :) For example: <xsl:value-of select="../node()/../TITLE"/> This says: from the current node (a TYPE attribute) go up to the parent (which will be a CONTENT element), then down to all its children, then up again to their parent (the same CONTENT element) and then get the value of its TITLE element child. So you're oscillating around needlessly. Instead, just use: <xsl:value-of select="../TITLE" /> Then you have: <xsl:for-each select="../node()/ROW/node()"> This says: from the current node (a TYPE attribute) go up to the parent (the CONTENT element), then get all its children, then get all their ROW element children (there will only be any if the node from the last step was a ROWS element), then down to all its children. Actually you just want the ROW element's element children. I think you'd be better off with: <xsl:for-each select="../ROWS/ROW/*"> Similarly further down, you have: <xsl:for-each select="../node()/ROW"> <tr bgcolor="#ffffff"> <xsl:for-each select="node()"> <td><xsl:value-of select="node()"/></td> </xsl:for-each> </tr> </xsl:for-each> Which I think would be clearer as: <xsl:for-each select="../ROWS/ROW"> <tr bgcolor="#ffffff"> <xsl:for-each select="*"> <td><xsl:value-of select="."/></td> </xsl:for-each> </tr> </xsl:for-each> You *can* use node() all the time, especially if you've made sure you're not counting whitespace-only text nodes by stripping them with: <xsl:strip-space elements="*" /> It might be slightly more efficient because the processor doesn't have to worry about testing to see whether the node is an element or whether it has a particular name, but it's probably less efficient in the long run because you end up collecting nodes that you don't want. It's also a lot harder to read, I think you'll agree. Oh, and the other thing is that you could avoid all those '..' to go up to the CONTENT element if the top-most xsl:for-each iterated over the CONTENT elements themselves rather than their TYPE attributes: <xsl:for-each select="CONTENT[@TYPE = 'DB']"> And you can skip the xsl:if that's wrapped around that xsl:for-each - it will only be processed anyway if it finds some elements to iterate on. > 3. I got most of the stuff to work on this page except for 1 > thing... on the XSL stylesheet, right after the <!---- ***** ----> > comment tag, I get duplicate <th></th> tags generated because the > loop I have there has no concept of uniqueness... so for the first > chunk, I get: > > <tr><th>NAME</th><th>EMAIL</th><th>NAME</th><th>EMAIL</th><th>NAME</th><th>E > MAIL</th></tr> > > instead of: > <tr><th>NAME</th><th>EMAIL</th></tr> (which is my desired output). Probably the easiest thing to do is to only get the children of the first of the ROW elements, and use their names, so use: <xsl:for-each select="../ROWS/ROW[1]/*"> <th><xsl:value-of select="name()"/></th> </xsl:for-each> >From your sample, the rest of the ROW elements have exactly the same children, so you only need look at the first one. If you do have different substructures for the ROW elements within a particular CONTENT, then you probably want: <xsl:for-each select="../ROWS/ROW/*"> <xsl:if test="not(../preceding-sibling::ROW/* [name() = name(current())])"> <th><xsl:value-of select="name()"/></th> </xsl:if> </xsl:for-each> This iterates over each of the element children of the ROW elements. It tests whether there are any element children of preceding ROW elements that have the same name() as the current node. If there aren't, then it gives the heading cell. I hope that helps, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|