BizTalk Utilities CV ,   Jobs ,   Code library
 
Home Page


Add/Edit your code items
Search the code library
Browse for the code library


XSLT
Binary Search in XSLT
Get the newest 5 articles out of hundreds -- a super efficient sort in XSLT
Dynamically change the encoding of your XSLT stylesheet
Identifying an attribute or a namespace node
Build a XPath expression for a node
Avoiding an XSLT Processor crash due to deep recursive processing
Conditional generation of a string in a single XPath expression
Re: Re: ABS function implemented as a single XPath expression
Re: ABS function implemented as a single XPath expression
ABS function implemented as a single XPath expression
XML to HTML text editor
Dynamically Selecting Which Element To Sort On Using Parameters
Avoid NaN in XPath sum() function
JScript Super Class To Handle XML Transformations
Test if a bit is on
Web Methodology (Layout Management)
Grouping an XML Node by First Letter
Dependent ComboBox in HTML build with XSLT
Re: How to use XSL function sum() to sum 2 XML fields
Re: How to use XSL function sum() to sum 2 XML fields


 
 

<< XQuery.NET and XML >>


By Dimitre Novatchev
First Posted 03/08/2001
Times viewed 314

Find all xsl:variables that are in scope?


Summary Imagine you're developing an XSLT debugger and need some way of finding and displaying all "xsl:variable"-s that are "visible" from the current node.

Is it at all possible to specify them using a single XPath expression? Read further to find out...

This is a real problem and here’s how it was specified by its author in the xslt mailing list:

Well it seems I've hit a small snag what I want is to get a list of variables in a scope so the closest is taken and passed on.  The XML looks something like:

<A>
  <P name=hello value=blue/>
  <P name=aval value=uppest/>
  <B>
  <P name=bval value=upper/>
  <P name=goodbye value=red/>
  <P name=hello value=green/>
  <C>
  <P name=goodbye value=yellow/>
 </C>
  <P name=abcdef value=orange/>
  <xxx>
  <P name=goodbye value=purple/>
</xxx>
</B>
<D>
<P name=goodbye value=red/>
  </D>
</A>

And my current context is C. With my output looking something like 
goodbye=yellow;hello=green;bval=upper;aval=uppest; 

So far I've got
<xsl:for-each select=ancestor-or-self::*/p[ what on earth can I put here ]>
  <xsl:value-of select=@name/>=<xsl:value-of select=@value/>;
</xsl:for-each> 

But I've got stuck in the way that MSXML3 seems to be serving up the axis in document order not reverse document order like it says on P717 or Michael Kays excellent book. Any and all help would be appreciated. 

A number of persons (actually some of the best experts) sent long XSLT codeor said some kind of recursive processing had to be used.  Let’s now concentrate on a pure XPath solution. 

It would be useful to have the XPath Visualizer already started (never heard of the XPath Visualizer? Hmmm… now I understand why XPath is so difficult to you… just give it a try and you’ll know what I mean.  

To verify that the sub-expressions we’d be building incrementally really behave as we’d expected them to. First of all, what does in scope mean? 
1. Well, any P that’s defined as a child of C-s parent or as a child of any of C-s ancestor nodes.

Why ancestor node and not just element? Because the root node / is a node – not an element –we’d like not to exclude any of the top-level <P>s.  Do you agree with the definition in 1.? Hmmm… not entirely – C will not be able to see any P children of its ancestors that are defined (follow) after C.  Therefore: 
2. Exclude from 1. all nodes following C 

Now the most important requirement: in case there are several P-s with the same nameattribute, we want just the innermost of these: 
3. Take from (1. and 2.) only such nodes, whose name is not duplicated in any of their descendents. 

Now we are ready to construct the whole XPath expression: 
For 1. we’ll have: 
//P[parent::C 
or count(.. | //C/ancestor::node())=count(//C/ancestor::node() )]

For 3. we have:
and not(@name=../descendant::node()/P/@name )

For 2. we have:
and count(. | //C/following::P) != count(//C/following::P )

So, let’s combine these together:
//P[parent::C 
or count(.. | //C/ancestor::node()) = count(//C/ancestor::node() ) 
and not(@name=../descendant::node()/P/@name ) 
and count(. | //C/following::P) != count(//C/following::P )]

Here I’m using the following to specify the fact that a node nd belongs to a node-set ns:
count(nd | ns) = count(ns)
and, similarly, to specify that nd does not belong to ns:
count(nd | ns) != count(ns)

In case you find it difficult to understand the last two expressions, do have a look at another snippet that explains the Kaysian method of intersecting two node-sets.

A last remark: We’re using //C here – just because we’re solving a particular example problem. For the general case simply replace this with current().

Additional information


Rate this article on a scale of 1 to 10 (0 votes, average 0)

Your vote :  

<< XQuery.NET and XML >>





Leave a comment for this article
Your name
Your email (optional)
Your comment
Optional: Upload an attachment
Enter the code shown:

 
 

    Email TopXML