xsl-list
[Top] [All Lists]

Data Recursion created by References

2003-04-10 13:47:48
All,

This question is mostly a design question. I'm wondering if someone else has run into a similar problem that I'm having with data that contains recursion within it. The format of my data is something like the following:

<object name="someObjectName">
 <childRef name="someReferenceToAnObject"/>
</object>

So, for a simple example I have the following. Note that to make this a well formed document, the top node contains all other nodes, but the referencing still applies.

<object name="a">
 <childRef name="b"/>
 <childRef name="c"/>
 <object name="b"><childRef name="a"/></object>
 <object name="c"><childRef name="d"/></object>
 <object name="d"><childRef name="b"/></object>
</object>

Specifically, I want to follow the data's path through a portion of the recursion. For example, suppose a webpage displays information about object 'a', and a user wishes to follow a link to the child node 'c'. The path to the object 'c' would be as follows:
a -> c

If the user continued to follow the child references, the user might end up with the following path to 'b':
   a -> c -> d -> b

Alternatively, the user might just end up wanting to follow the reference to 'b' initially:
   a -> b

Is there a mechanism/algorithm for distinguishing between these two paths that can be implemented within xslt?

If I modified the xml slightly, there is an alternative problem:
<object name="a">
 <childRef name="b"/>
 <childRef name="c"/>
 <object name="b"><childRef name="c"/></object>
 <object name="c"><childRef name="d"/></object>
 <object name="d"/>
</object>

How do I distinguish between:
   a -> b -> c -> d
and
   a -> d

Currently, I reference the objects through a key that identifies each object individually, but unfortunately this doesn't help me determine which path was used. What I'd like to do is reference the object by it's path through the child references as opposed to the unique object. I believe there is a solution that addresses both problems, but I haven't found it yet. Has anyone run across a problem similar to this that might be able to provide some help?

Thanks,
bix

I orginally designed my xsl without taking multiple references to the same object into consideration.
Within the XSL that follows, this line enforces just a single reference:
<x:with-param name="currNode" select="exslt:node-set($parentNodes)[1]"/>


The following is my XSL.
<!-- xmlns:exslt="urn:schemas-microsoft-com:xslt" -->
<!-- xmlns:exslt="http://www.exslt.org"; -->

<x:stylesheet version="1.0"
 xmlns:x="http://www.w3.org/1999/XSL/Transform";
 xmlns:exslt="urn:schemas-microsoft-com:xslt"


 <x:output indent="yes" method="html"/>

 <x:key name="objectsKey" match="object" use="@name"/>
 <x:key name="childrenKey" match="object" use="childRef/@name"/>
 <x:param name="startNodeName" select="'d'"/>
 <x:param name="topNodeName" select="'a'"/>
 <x:param name="startNode" select="//object[(_at_)name = $startNodeName]"/>
 <x:param name="topNode" select="//object[(_at_)name = $topNodeName]"/>

 <x:attribute-set name="hiddenTable">
   <x:attribute name="border">0</x:attribute>
   <x:attribute name="cellspacing">0</x:attribute>
   <x:attribute name="cellpadding">0</x:attribute>
 </x:attribute-set>

 <x:attribute-set name="fillWindow">
   <x:attribute name="style">margin: 0;</x:attribute>
 </x:attribute-set>

 <x:template match="/">
   <x:element name="startNodeName">
<x:attribute name="name"><x:value-of select="$startNodeName"/></x:attribute>
   </x:element>
   <x:apply-templates select="object"/>
 </x:template>

 <x:template match="object">
   <x:element name="html">
     <x:element name="head">
       <x:element name="title">Autogenerated Webview</x:element>
       <x:element name="style">
         <![CDATA[
           a {text-decoration:none}
         ]]>
       </x:element>
       <x:element name="script">
         <![CDATA[
   var xmlObj = null;
   var xslObj = null;
   var xformer = null;

   function getXMLObj(xmlFileName) {
       xmlObj = new ActiveXObject("Msxml2.DOMDocument.4.0");
       xmlObj.async = false;
       xmlObj.validateOnParse = true;
       xmlObj.load(xmlFileName);
       return xmlObj;
   }

   function getXSLObj(xslFileName) {
       xslObj = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.4.0");
       xslObj.async = false;
       xslObj.validateOnParse = true;
       xslObj.load(xslFileName);
       return xslObj;
   }

   function getTransformer(xmlObject, xslObject) {
       var template = new ActiveXObject("MSXML2.XSLTemplate.4.0");
       template.stylesheet = xslObject.documentElement;
       var transformer = template.createProcessor();
       transformer.input = xmlObject;
       return transformer;
   }

   function init()
   {
       xmlObj = getXMLObj("temp.xml");
       xslObj = getXSLObj("temp.xsl");
   }

   function refresh(id,w)
   {
       var xformer = getTransformer(xmlObj,xslObj);
       xformer.addParameter("startNodeName", id, "");
       xformer.transform();
       w.write(xformer.output);
       w.close();
   }
         ]]>
       </x:element>
     </x:element>
     <x:element name="body" use-attribute-sets="fillWindow">
       <x:attribute name="onload">javascript:init()</x:attribute>
       <x:element name="table" use-attribute-sets="hiddenTable">
         <x:element name="tr">
           <x:element name="td">
             <x:call-template name="makePath">
               <x:with-param name="currNode" select="$startNode"/>
             </x:call-template>
           </x:element>
         </x:element>
       </x:element>
     </x:element>
   </x:element>
 </x:template>

 <x:template name="makePath">
   <x:param name="topNode" select="$topNode"/>
   <x:param name="currNode" select="."/>
   <x:param name="currNodeName" select="exslt:node-set($currNode)/@name"/>
   <x:param name="parentNodes" select="key('childrenKey', $currNodeName)"/>
   <x:choose>
<x:when test="(exslt:node-set($parentNodes)) or (generate-id($topNode) != generate-id($currNode))">
       <x:call-template name="makePath">
<x:with-param name="currNode" select="exslt:node-set($parentNodes)[1]"/>
       </x:call-template>
       <x:call-template name="addSpacer"/>
       <x:call-template name="showNode">
         <x:with-param name="node" select="$currNode"/>
       </x:call-template>
     </x:when>
     <x:otherwise>
       <x:call-template name="showNode">
         <x:with-param name="node" select="$currNode"/>
       </x:call-template>
     </x:otherwise>
   </x:choose>
 </x:template>

 <x:template name="showNode">
   <x:param name="node" select="."/>
   <x:element name="a">
<x:attribute name="href">javascript:refresh('<x:value-of select="exslt:node-set($node)/@name"/>',this.document)</x:attribute>
     <x:element name="font">
       <x:attribute name="face">Arial</x:attribute>
       <x:value-of select="exslt:node-set($node)/@name"/>
     </x:element>
   </x:element>
 </x:template>

 <x:template name="addSpacer">
   &#160;
   <x:element name="font">
     <x:attribute name="face">Wingdings</x:attribute>&#xF0;</x:element>
   &#160;
 </x:template>
</x:stylesheet>


_________________________________________________________________
The new MSN 8: smart spam protection and 2 months FREE* http://join.msn.com/?page=features/junkmail


XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



<Prev in Thread] Current Thread [Next in Thread>
  • Data Recursion created by References, bix xslt <=