469,917 Members | 1,458 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,917 developers. It's quick & easy.

Grouping, duplicates Muenchian appears to fail

7
I’m relatively new to XSLT and must admit I’m finding it refreshing, but every now and again something comes along which floors me. Maybe it’s the old imperative language background that is hard to shake. This is an example of a dark cloud in my brave new declarative world. Clearing duplication is bread and butter but in XSLT it’s not. The old preceding axis method is both too slow and destined to failure. The Muenchian method, although sublime to the novice also seems to become unstuck (have I missed something obvious). I cast my sanity and naivety over to the community.

The XML included is a psuedo subset of a much larger file, which is generated from a network management system. Each submap tag contains a collection of devices and essentially other submaps which in-turn can contain a collection of devices and submaps and so on.

The problem is, given a submap level that can be passed as a parameter into the stylesheet. I need to form a unduplicated list of groups ( node grps) contained within the submap nodes at the current context of interest. This includes submaps which are descendants of each of the submaps of the context of interest. Let me get the XML and an example of the target output needed this is getting too wordy already.


XML

Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <root>
  3.     <submap name="A">
  4.         <device>
  5.             <devname>rtr001</devname>
  6.             <grp>router</grp>
  7.         </device>
  8.         <submap name="E">
  9.             <device>
  10.                 <devname>rtr005</devname>
  11.                 <grp>router</grp>
  12.             </device>
  13.             <device>
  14.                 <devname>SW0001</devname>
  15.                 <grp>switch</grp>
  16.             </device>
  17.         </submap>
  18.     </submap>
  19.     <submap name="B">
  20.         <submap name="F">
  21.             <submap name="G">
  22.                 <submap name="H">
  23.                     <device>
  24.                         <devname>ftp003</devname>
  25.                         <grp>ftpserver</grp>
  26.                     </device>
  27.                     <device>
  28.                         <devname>www001</devname>
  29.                         <grp>webserver</grp>
  30.                     </device>
  31.                 </submap>
  32.                 <device>
  33.                     <devname>rtr007</devname>
  34.                     <grp>router</grp>
  35.                 </device>
  36.                 <device>
  37.                     <devname>SW0002</devname>
  38.                     <grp>switch</grp>
  39.                 </device>
  40.                 <device>
  41.                     <devname>rtr006</devname>
  42.                     <grp>router</grp>
  43.                 </device>
  44.                 <device>
  45.                     <devname>srv001</devname>
  46.                     <grp>server</grp>
  47.                 </device>
  48.             </submap>
  49.         </submap>
  50.         <device>
  51.             <devname>rtr002</devname>
  52.             <grp>router</grp>
  53.         </device>
  54.         <submap name="I">
  55.             <device>
  56.                 <devname>rtr005</devname>
  57.                 <grp>router</grp>
  58.             </device>
  59.             <device>
  60.                 <devname>hub001</devname>
  61.                 <grp>hub</grp>
  62.             </device>
  63.         </submap>
  64.     </submap>
  65.     <submap name="C">
  66.         <submap name="j">
  67.             <device>
  68.                 <devname>rtr006</devname>
  69.                 <grp>router</grp>
  70.             </device>
  71.             <device>
  72.                 <devname>av0001</devname>
  73.                 <grp>antivirus</grp>
  74.             </device>
  75.         </submap>
  76.         <device>
  77.             <devname>rtr003</devname>
  78.             <grp>router</grp>
  79.         </device>
  80.     </submap>
  81.     <submap name="D">
  82.         <device>
  83.             <devname>rtr004</devname>
  84.             <grp>router</grp>
  85.         </device>
  86.         <device>
  87.             <devname>pop001</devname>
  88.             <grp>mailserver</grp>
  89.         </device>
  90.     </submap>
  91. </root>
Target Output ( using target submap B – Context node)

Groups for submaps in B context.

Submap F - router ftpserver,webserver,switch,server
Submap I – router,hub




What I can get, and what I have tried and failed at

What is possible?

A list of all down stream grps split by submap but containing duplicates.

Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0"?>
  2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  3. <xsl:param name="targetsubmap">B</xsl:param>
  4.  
  5. <xsl:template match="/">
  6. <xsl:apply-templates select="//submap[@name=$targetsubmap]" mode="test"/>
  7. </xsl:template>
  8.  
  9. <xsl:template match="submap" mode="test">
  10. <xsl:text>
  11. Groups for submaps in </xsl:text><xsl:value-of select="@name"/><xsl:text> context.
  12. </xsl:text>
  13. <xsl:apply-templates select="submap" mode="level">
  14. </xsl:apply-templates>
  15. </xsl:template>
  16. <xsl:template match="submap" mode="level">
  17. <xsl:text>
  18. Submap </xsl:text>
  19. <xsl:value-of select="@name"/><xsl:text> - </xsl:text>
  20. <xsl:for-each select="descendant::grp">
  21. <xsl:value-of select="."/>
  22. <xsl:if test="position() != last()">,</xsl:if>
  23. </xsl:for-each>
  24. </xsl:template>
  25.  
  26. </xsl:stylesheet>

Output

Groups for submaps in B context.

Submap F - ftpserver,webserver,router,switch,router,server
Submap I - router,hub

Note router is duplicated in submap F list, it should be in submap I list

What also fails.

The Muenchian Method

Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0"?>
  2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  3. <xsl:param name="targetsubmap">B</xsl:param>
  4. <xsl:key name="kdgroups" match="//device" use="grp"/>
  5.  
  6. <xsl:template match="/">
  7. <xsl:apply-templates select="//submap[@name=$targetsubmap]" mode="test"/>
  8. </xsl:template>
  9.  
  10. <xsl:template match="submap" mode="test">
  11. <xsl:text>
  12. Groups for submaps in </xsl:text><xsl:value-of select="@name"/><xsl:text> context.
  13. </xsl:text>
  14. <xsl:apply-templates select="submap" mode="level">
  15. </xsl:apply-templates>
  16. </xsl:template>
  17.  
  18. <xsl:template match="submap" mode="level">
  19. <xsl:text>
  20. Submap </xsl:text>
  21. <xsl:value-of select="@name"/><xsl:text> - </xsl:text>
  22. <xsl:for-each select="descendant::device[generate-id(.)=generate-id(key('kdgroups',grp))]">
  23. <xsl:value-of select="grp"/>
  24. <xsl:if test="position() != last()">,</xsl:if>
  25. </xsl:for-each>
  26. </xsl:template>
  27.  
  28. </xsl:stylesheet>
OUTPUT

Groups for submaps in B context.

Submap F - ftpserver,webserver,server
Submap I - hub

This seems to fail because, once an id is generated(see what happens to the router group) it is no longer available to subsequent submaps so it is not included within the output tree as needed. Adding the context to the key declaration would reduce the amount of elements the key is applied to but would still fail. The router and switch groups would appear in the submap F list but not the submap I list as needed. Also the context is passed in as a parameter that cannot appear in the match clause of the key declaration.

The preceding axis solution as per O’Reiley Cookbook – although probably way to slow on a larger file. I attempted this method just in-case. It fails for the same reason as the Muenchian Method. Can any one explain the trailing comma?

Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0"?>
  2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  3. <xsl:param name="targetsubmap">B</xsl:param>
  4.  
  5. <xsl:template match="/">
  6. <xsl:apply-templates select="//submap[@name=$targetsubmap]" mode="test"/>
  7. </xsl:template>
  8.  
  9. <xsl:template match="submap" mode="test">
  10. <xsl:text>
  11. Groups for submaps in </xsl:text><xsl:value-of select="@name"/><xsl:text> context.
  12. </xsl:text>
  13. <xsl:apply-templates select="submap" mode="level">
  14. </xsl:apply-templates>
  15. </xsl:template>
  16.  
  17. <xsl:template match="submap" mode="level">
  18. <xsl:text>
  19. Submap </xsl:text>
  20. <xsl:value-of select="@name"/><xsl:text> - </xsl:text>
  21. <xsl:for-each select="descendant::grp">
  22. <xsl:sort select="."/>
  23. <xsl:if test="not(self::node()=preceding::node())">
  24. <xsl:value-of select="."/>
  25. <xsl:if test="position() != last()">,</xsl:if>
  26. </xsl:if>
  27. </xsl:for-each>
  28. </xsl:template>
  29.  
  30. </xsl:stylesheet>

Output

Groups for submaps in B context.

Submap F - ftpserver,server,webserver
Submap I - hub,

If anybody finds a solution which requires the source XML to be altered this is ok as I wrote the Interface to the Network Management System so I can change it. I should note that the XML you can see is a massively simplified abstraction to demonstrate the point. Basically if I have to change it I will.

Hopefully thanks for the help, let me know any methods you have tried even if they fail so I can tick them of the list. I’m hoping I have misunderstood Muenchian.
Oct 6 '05 #1
1 2409
rayt
7
At last I’ve got the swine, well almost, I need to fix the trailing comma (<xsl:if test="position() != last()">,</xsl:if> does not work as I cannot guarantee position).


I know it probably has flaws but it works. If anybody has a better way could you let me know or if anybody knows a clever way to get rid of the trailing comma I’d be grateful.


Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0"?>
  2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  3. <xsl:param name="targetsubmap">B</xsl:param>
  4. <xsl:key name="kdgroups" match="//device" use="grp"/>
  5.  
  6. <xsl:template match="/">
  7. <xsl:apply-templates select="//submap[@name=$targetsubmap]" mode="test"/>
  8. </xsl:template>
  9.  
  10. <xsl:template match="submap" mode="test">
  11. <xsl:text>
  12. Groups for submaps in </xsl:text><xsl:value-of select="@name"/><xsl:text> context.
  13. </xsl:text>
  14. <xsl:apply-templates select="submap" mode="level">
  15. </xsl:apply-templates>
  16. </xsl:template>
  17.  
  18. <xsl:template match="submap" mode="level">
  19. <xsl:variable name="cursub" select="."/>
  20. <xsl:variable name="totgrps" select="//device[generate-id(.)=generate-id(key('kdgroups',grp))]"/>
  21. <xsl:text>
  22. Submap </xsl:text>
  23. <xsl:value-of select="@name"/>
  24. <xsl:text> - </xsl:text>
  25. <xsl:for-each select="$totgrps">
  26. <xsl:variable name="loopgrp" select="grp"/>
  27. <xsl:for-each select="$cursub">
  28. <xsl:if test="count(descendant::device[grp=$loopgrp]) > 0">
  29. <xsl:value-of select="$loopgrp"/>
  30. <xsl:text>,</xsl:text>
  31. </xsl:if>
  32. </xsl:for-each>
  33. </xsl:for-each>
  34. </xsl:template>
  35.  
  36. </xsl:stylesheet>
Oct 9 '05 #2

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

3 posts views Thread by Bryce (Work) | last post: by
3 posts views Thread by Graham | last post: by
2 posts views Thread by Tristan Miller | last post: by
4 posts views Thread by kristofera | last post: by
6 posts views Thread by Per Jørgen Vigdal | last post: by
2 posts views Thread by Andreas Håkansson | last post: by
1 post views Thread by Sandeep Singh | last post: by
reply views Thread by Salome Sato | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.