This is Interesting: Free Magazines for Graphics designers and webmasters
Home > Archive > Microsoft XML > August 2006 > Any simple way to obtain a "dynamically-defined" nodeset?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Any simple way to obtain a "dynamically-defined" nodeset?
|
|
|
| Hello,
I am not sure the subject of my post adequately describes the problem I
am trying to solve, so I think a specific example would be helpful.
Let's say there are XML descriptions of products like this one:
<!-- File: Products.xml -->
...
<Product id="p1">
<Title>....</Title>
...
<PricingInfo>
<RegularPrice>100</RegularPrice>
<Discount>25</Discount>
...
</PricingInfo>
...
<ShippingInfo>
<Cost>9.95</Cost>
<MaxDelay>1 business day</MaxDelay>
...
</ShippingInfo>
...
</Product>
The key thing here is that the schema of <Product> is not "flat" - it
contains elements with subelements, which may also have subelements,
and so on...
Now, let's say that I want to have an XML file that describes some sort
of an HTML page template which, in particular, refers to certain
attributes of <Product>s. Something along these lines:
<!-- File: PageTemplate.xml -->
...
<section>General</section>
<p>Title: <ProductProperty rxpath="Title"/></p>
<section>Shipping Info</section>
<p>Cost: <ProductProperty rxpath="ShippingInfo/Cost"/></p>
<p>Delay: <ProductProperty rxpath="ShippingInfo/Delay"/></p>
...
Finally, in an XSL file, whose templates are supposed to be applied to
PageTemplate.xml, I would like to write something like this:
<!-- File: ProductPage.xsl -->
...
<xs:template match="ProductProperty">
<!-- The parameter contains a nodeset from Products.xml -->
<!-- Or there could be a variable with the same contents... -->
<xs:param name="nsProduct" tunnel="yes"/>
<!-- And below is where the fun begins... -->
<xs:apply-templates
select="$nsProduct/*[name()=current()/@rxpath]"/>
</xs:template>
The problem is: I do not know what could I specify the @select
attribute of the <xs:apply-templates> element to retrieve exactly the
sub-nodeset of <Product> element defined by the @rxpath attribute of
the <ProductProperty> element.
The expression I wrote above -- $nsProduct/*[name()=current()/@rxpath]
-- works fine for @rxpaths that specify direct children of the
<Product> element (like "Title"), but obviously does not work for any
ancestor elements (like "ShippingInfo/Cost"). So I guess I am looking
for a way to dynamically obtain a sub-nodeset of a specified "origin
nodeset" (in my example, it is defined by $nsProduct) using specified
"subpath" inside that nodeset.
In some sense, the problem is similar to what XForms are trying to
achieve: provide XML description of a data model, XML description of a
view of that data model, and bindings between view elements and data
model elements. In my case, "bindings" are supposed to be very
simplistic - just plain relative XPath expressions...
If anyone knows the trick that could let me do what I want (or
something really close to what I want) using XSLT 2.0 and XPath 2.0,
please advise. In fact, any comments would be appreciated.
Thank you,
Yarik.
| |
| Neil Smith [MVP Digital Media] 2006-08-21, 6:42 pm |
| On 21 Aug 2006 11:59:14 -0700, "Yarik" <yarik@garlic.com> wrote:
>The expression I wrote above -- $nsProduct/*[name()=current()/@rxpath]
>-- works fine for @rxpaths that specify direct children of the
><Product> element (like "Title"), but obviously does not work for any
>ancestor elements (like "ShippingInfo/Cost"). So I guess I am looking
>for a way to dynamically obtain a sub-nodeset of a specified "origin
>nodeset" (in my example, it is defined by $nsProduct) using specified
>"subpath" inside that nodeset.
I believe you just want to match "any" ShippingInfo/Cost, at any
level. XPath has a match for that, which would be similar to
$nsProduct//ShippingInfo/Cost
Note the double slash to select ancestor elementsor $nsProduct at any
level. [It's the same double slash used if you did //ShippingInfo/Cost
which would travese from the document root to any ShippingInfo Cost
node at all)
HTH
Cheers - Neil
------------------------------------------------
Digital Media MVP : 2004-2006
http://mvp.support.microsoft.com/mvpfaqs
| |
| Joe Kesselman 2006-08-21, 10:35 pm |
| Dynamic interpretation of XPaths from variables is not supported in XSLT
.... but may be possible in some specific processors via extension
functions. See
http://www.exslt.org/dyn/
Instead, I'd consider writing your "template file" so it can be executed
directly as a stylesheet. One approach to doing so is shown in the XSLT
spec itself:
http://www.w3.org/TR/xslt#result-element-stylesheet
Or, if you really want to separate the binding stage from the styling
stage, you could consider two-pass transformation -- one pass to extract
the data and put it in standard form, and a second to get it from that
into your presentation form.
--
() ASCII Ribbon Campaign | Joe Kesselman
/\ Stamp out HTML e-mail! | System architexture and kinetic poetry
| |
|
| Joe, thank you much for quick and thorough response!
Joe Kesselman wrote:
> Dynamic interpretation of XPaths from variables is not supported
> in XSLT ... but may be possible in some specific processors
> via extension functions.
I'm using Saxon, and it does not seem to support dyn: extensions. But,
even if it did, using EXSLT would be my last resort. (Or next to last.
:-))
> Instead, I'd consider writing your "template file" so it can be executed
> directly as a stylesheet. One approach to doing so is shown in the XSLT
> spec itself:
> http://www.w3.org/TR/xslt#result-element-stylesheet
This probably would be my first choice should I lose my battle for "a
la XForms" approach...
> Or, if you really want to separate the binding stage from the styling
> stage, you could consider two-pass transformation...
I guess, this would be my second choice...
In the meantime, I did some quick-and-dirty experiments and... it turns
out that "vanilla" XSLT 2.0 is not as weak as I thought. If anyone is
interested, my experiment yielded the following interesting, yet very
simple, custom function (i.e. function template):
<xs:function name="custom:path" xmlns:custom="custom">
<xs:param name="nsNode"/>
<xs:param name="nsRoot"/>
<xs:if test="not($nsNode is $nsRoot)">
<xs:value-of
select="concat(custom:path($nsNode/parent::node(),$nsRoot), '/',
name($nsNode))"/>
</xs:if>
</xs:function>
It takes two nodes and returns a string that represents a path from
$nsRoot to $nsNode (assuming that $nsNode is a descendant of $nsRoot).
Now, taking my initial example, I can use this nice function like this:
<xs:template match="ProductProperty">
<!-- The parameter contains a nodeset from Products.xml -->
<!-- Or there could be a variable with the same contents... -->
<xs:param name="nsProduct" tunnel="yes"/>
<!-- And below is where the fun begins... -->
<xs:apply-templates select="$nsProduct/*[custom:path(.,
$nsProduct) = current()/@rxpath]"/>
</xs:template>
Maybe this is not the most elegant way to do it, but it appears to be
working just fine. Moreover, I suspect that, with some additional
effort, this function could be enhanced to handle more intricate cases.
But... at 4 o'clock in the morning I would not bet my head on this...
:-)
The more I use XSLT 2.0, the more I like it (and the more XSLT 1.0
feels like a stone-age tool :-).
| |
|
| Neil Smith [MVP Digital Media] wrote:
> On 21 Aug 2006 11:59:14 -0700, "Yarik" <yarik@garlic.com> wrote:
>
> I believe you just want to match "any" ShippingInfo/Cost, at any
> level. XPath has a match for that, which would be similar to
>
> $nsProduct//ShippingInfo/Cost
I guess I did not convey the crux of my problem clearly. The key issue
is that the xpath to the desired ancestor of $nsProduct is specified in
a parameter (or in a variable). In other words, I need to find an
ancestor of $nsProduct whose relative xpath is not known until the
actual processing happens. That's what I meant by "dynamically-defined
nodeset"...
Still, I really appreciate you help, Neil. Thank you!
BTW, it looks like I did find some solution: see my response to Joe's
posting below...
|
|
|
| | Copyright 2003 - 2008 forum4designers.com Software forum Computer Hardware reviews |
|