Re: [xsl] Re: How to handle dynamic XPath

Subject: Re: [xsl] Re: How to handle dynamic XPath
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Mon, 13 Apr 2009 06:46:49 -0700
> Mike's solution works, although I would prefer a solution without extension
> functions.

One could use the FXSL LR-Parsing framework to create an XPath parser.

This is what I did more than an year ago (an XPath 2.0) parser, and
already forgot about it -- could find no use for it until recently,
when Florent asked for the parser with the intent to use it for
hi-lighting XPath expressions.

Another use could be to convert a complicated XPath expression into
corresponding equivalent XSLT instructions -- for people who prefer
the XSLT-oriented syntax over the XPath-oriented one.

Or, if we could use the XPath 2.0 grammer to *synthesize* XPath
expressions, then one could create an app. to convert XSLT to an XPath
expression. Anyone heard of a usable instance generator, as opposed to
a parser, using a grmmar definition?



--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
Never fight an inanimate object
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play



On Sun, Apr 12, 2009 at 11:28 PM,  <fred@xxxxxxxxxxxxx> wrote:
> This list is incredible!
> I was struggling all Easter sunday with a problem, posted it, went to sleep
> and overnight three experts came with solutions. Thank you, Ken, Michael
and
> Florent!
>
> Mike's solution works, although I would prefer a solution without extension
> functions.
> Keeping a key table as Ken suggests is a bit difficult, as beforehand
> (design time) I do not know the structure of the documents. The XSL takes
> any XML schema that obeys certain rules of well-formedness. Creating the
key
> table at run time could be a solution though.
> Florents suggestion of a meta-stylesheet is worth wile investigating, but
> that would complicate the application even more.
>
> Hope I didnt spoil your Easter too much.
>
> Fred
>
>
>
>
>> ------------------------------
>>
>> Date: Sun, 12 Apr 2009 21:07:29 +0200
>> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
>> From: fred@xxxxxxxxxxxxx
>> Subject: How to handle dynamic XPath
>> Message-ID: <20090412210729.uv66b6hsw0sgksw0@xxxxxxxxxxxxxxxxxxxxx>
>>
>> Hi,
>>
>> I am using XSLT to walk through an XML Schema to construct an Xforms =20
>> (output) instance.
>> In parallel I am scanning an (input) instance (of a document defined =20
>> by the schema) to
>> include default values in the form.
>>
>> Scanning of the input instance is done by means of a variable that =20
>> keeps track of the
>> path. The variable is updated (renewed) each time a template is =20
>> (recursively) called with
>> the variable as parameter:
>>
>> <xsl:with-param name=3D"instance.path"
>> select=3D"concat($instance.path,'/',$element.prefix,':',@name)" />
>>
>> The template calls another template that writes the output instance. =20
>> In that template I
>> try to look up the default value in the input instance (an external
>> document=
>> ).
>>
>> BUT:
>>
>> <xsl:value-of select=3D"document('file:/C:/dir/order.xml')/$instance.path"
>> /=
>>>
>> writes a path string to the output instance instead of the value of =20
>> the element, such as:
>> /rsm:PurchaseOrder/rsm:Identifier, so does copy-of select.
>>
>> <xsl:value-of
>> select=3D"document('file:/C:/dir/order.xml')//rsm:DeliveryDate=
>> " />
>> writes correctly the content of the delivery date, but
>> <xsl:value-of select=3D"document('file:/C:/dir/order.xml')//$deldate" />
>> (where $deldate contains the string "rsm:DeliveryDate") writes nothing.
>>
>> Concluding the problem is node-format vs text format, I tried the =20
>> saxon evaluate
>> function, but:
>> <xsl:copy-of =20
>>
>>
select=3D"saxon:evaluate(document('file:/C:/dir/order.xml')/$instance.path)"=
>> B =20
>> />
>> writes nothing, neither does value-of.
>>
>> I am desperate. Does anyone have a clue how to solve this?
>>
>> Thanks in advance,
>>
>> Fred van Blommestein
>>
>> ------------------------------
>>
>> Date: Sun, 12 Apr 2009 15:34:14 -0400
>> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
>> From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
>> Subject: Re: [xsl] How to handle dynamic XPath
>> Message-Id: <7.0.1.0.2.20090412152437.02699d30@xxxxxxxxxxxxxxxxxxxxxx>
>>
>> At 2009-04-12 21:07 +0200, fred@xxxxxxxxxxxxx wrote:
>>>
>>> I am using XSLT to walk through an XML Schema to construct an Xforms
>>> (output) instance.
>>> In parallel I am scanning an (input) instance (of a document defined
>>> by the schema) to
>>> include default values in the form.
>>
>> I'm assuming the structures of the two documents are identical.
>>
>>> Scanning of the input instance is done by means of a variable that
>>> keeps track of the
>>> path. The variable is updated (renewed) each time a template is
>>> (recursively) called with
>>> the variable as parameter:
>>>
>>> <xsl:with-param name="instance.path"
>>> select="concat($instance.path,'/',$element.prefix,':',@name)" />
>>>
>>> The template calls another template that writes the output instance.
>>> In that template I
>>> try to look up the default value in the input instance (an external
>>> B document).
>>>
>>> BUT:
>>>
>>> <xsl:value-of select="document('file:/C:/dir/order.xml')/$instance.path"
>>> />
>>> writes a path string to the output instance instead of the value of
>>> the element, such as:
>>> /rsm:PurchaseOrder/rsm:Identifier, so does copy-of select.
>>
>> Correct, because there is no such thing as "eval()" in XPath. B The
>> final step of your XPath address is the value of a variable, so you
>> are getting the value of the variable as you should.
>>
>> And who is to say that your prefixes in your input document match the
>> prefixes in your default value document?
>>
>>> <xsl:value-of
>>> B select="document('file:/C:/dir/order.xml')//rsm:DeliveryDate" />
>>> writes correctly the content of the delivery date, but
>>> <xsl:value-of select="document('file:/C:/dir/order.xml')//$deldate" />
>>> (where $deldate contains the string "rsm:DeliveryDate") writes nothing.
>>
>> I would expect you to see the string "rsm:DeliveryDate", not nothing.
>>
>>> Concluding the problem is node-format vs text format, I tried the
>>> saxon evaluate
>>> function, but:
>>> <xsl:copy-of
>>>
>>>
select="saxon:evaluate(document('file:/C:/dir/order.xml')/$instance.path)"
>>> />
>>> writes nothing, neither does value-of.
>>>
>>> I am desperate. Does anyone have a clue how to solve this?
>>
>> You could use a key table, where the lookup value for each element is
>> that element's fully-qualified XPath address. B And you could use the
>> "{namespace-uri}local-name" syntax for each element in the path in
>> order to be independent of namespace prefixes.
>>
>> Then you use:
>>
>> B <xsl:value-of select="document('file:/C:/dir/order.xml')/
>> B  B  B  B  B  B  B  B  B  B  B  B key('myTable',$instance.path))"/>
>>
>> and it will return the value of the element.
>>
>> You don't give any sample data to test with, and you don't talk about
>> sibling elements of the same name, but I think this approach would
>> work for you. B An example is below where each element of fred.xml is
>> replaced with the corresponding value from fred-default.xml.
>>
>> I hope this helps.
>>
>> . . . . . . . . . . . . . Ken
>>
>> T:\ftemp>type fred.xml
>> <a xmlns="urn:x-fred">
>> B  <b>B1</b>
>> B  <c>C1</c>
>> B  <b>B2</b>
>> B  <d>
>> B  B  <e>E1</e>
>> B  </d>
>> </a>
>> T:\ftemp>type fred-default.xml
>> <f:a xmlns:f="urn:x-fred">
>> B  <f:b>def-B1</f:b>
>> B  <f:c>def-C1</f:c>
>> B  <f:b>def-B2</f:b>
>> B  <f:d>
>> B  B  <f:e>def-E1</f:e>
>> B  </f:d>
>> </f:a>
>> T:\ftemp>call xslt2 fred.xml fred.xsl
>> <?xml version="1.0" encoding="UTF-8"?><a xmlns="urn:x-fred">
>> B  <b>def-B1</b>
>> B  <c>def-C1</c>
>> B  <b>def-B2</b>
>> B  <d>
>> B  B  <e>def-E1</e>
>> B  </d>
>> </a>
>> T:\ftemp>type fred.xsl
>> <?xml version="1.0" encoding="US-ASCII"?>
>> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>> B  B  B  B  B  B  B  B  xmlns:f="urn:x-fred"
>> B  B  B  B  B  B  B  B  version="2.0">
>>
>> <xsl:key name="paths" match="*" use="f:make-path(.)"/>
>>
>> <!--walk the element tree-->
>> <xsl:template match="*">
>> B  <xsl:param name="path"/>
>> B  <!--determine the path to this element-->
>> B  <xsl:variable name="this-path"
>> B  B  B  B  B  B  B  B  select="concat($path,f:make-step(.))"/>
>> B  <!--preserve the element structure-->
>> B  <xsl:copy>
>> B  B  <!--preserve any attributes-->
>> B  B  <xsl:apply-templates select="@*"/>
>> B  B  <!--replace the value when there are no element children-->
>> B  B  <xsl:choose>
>> B  B  B  <xsl:when test="not(*)">
>> B  B  B  B  <!--at a leaf element-->
>> B  B  B  B  <xsl:value-of select="document('fred-default.xml')/
>> B  B  B  B  B  B  B  B  B  B  B  B  B  B  B  key('paths',$this-path)"/>
>> B  B  B  </xsl:when>
>> B  B  B  <xsl:otherwise>
>> B  B  B  B  <!--at a branch element, keep going-->
>> B  B  B  B  <xsl:apply-templates>
>> B  B  B  B  B  <xsl:with-param name="path" select="$this-path"/>
>> B  B  B  B  </xsl:apply-templates>
>> B  B  B  </xsl:otherwise>
>> B  B  </xsl:choose>
>> B  </xsl:copy>
>> </xsl:template>
>>
>> <!--identity for all other nodes-->
>> <xsl:template match="@*|comment()|processing-instruction()">
>> B  <xsl:copy/>
>> </xsl:template>
>>
>> <!--create a lookup key-->
>> <xsl:function name="f:make-path">
>> B  <xsl:param name="element"/>
>> B  <xsl:sequence select="string-join( for $e in
>> $element/ancestor-or-self::*
>> B  B  B  B  B  B  B  B  B  B  B  B  B  B  B  B  B  B  B return f:make-step(
$e ), '' )"/>
>> </xsl:function>
>>
>> <xsl:function name="f:make-step">
>> B  <xsl:param name="element"/>
>> B  <xsl:for-each select="$element">
>> B  B  <xsl:sequence
select="concat('/{',namespace-uri(.),'}',local-name(.),
>>
>> B '[',count(preceding-sibling::*[node-name(.)=node-name(current())])+1,
>> B  B  B  B ']')"/>
>> B  </xsl:for-each>
>> </xsl:function>
>>
>> </xsl:stylesheet>
>>
>> T:\ftemp>rem Done!
>>
>> --
>> XSLT/XSL-FO/XQuery training in Los Angeles (New dates!) 2009-06-08
>> Training tools: Comprehensive interactive XSLT/XPath 1.0/2.0 video
>> Video lesson: B  B http://www.youtube.com/watch?v=PrNjJCh7Ppg&fmt=18
>> Video overview: B http://www.youtube.com/watch?v=VTiodiij6gE&fmt=18
>> G. Ken Holman B  B  B  B  B  B  B  B  mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
>> Crane Softwrights Ltd. B  B  B  B  B http://www.CraneSoftwrights.com/s/
>> Male Cancer Awareness Nov'07 B http://www.CraneSoftwrights.com/s/bc
>> Legal business disclaimers: B http://www.CraneSoftwrights.com/legal
>>
>> ------------------------------
>>
>> Date: Sun, 12 Apr 2009 23:35:31 +0100
>> To: <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
>> From: "Michael Kay" <mike@xxxxxxxxxxxx>
>> Subject: RE: [xsl] How to handle dynamic XPath
>> Message-ID: <4FA95E4459EE4A4B85EEF35A0C54B439@Sealion>
>>
>>> Concluding the problem is node-format vs text format, I tried
>>> the saxon evaluate function, but:
>>> <xsl:copy-of
>>> select="saxon:evaluate(document('file:/C:/dir/order.xml')/$ins
>>> tance.path)"
>>> />
>>> writes nothing, neither does value-of.
>>
>> You're on the right lines here, but the syntax would be
>>
>> select="document('file:/C:/dir/order.xml')/saxon:evaluate($instance.path)"
>>
>> I strongly suspect that there are much better solutions to this problem
>> that
>> don't involve dynamic evaluation. However, it's Easter Sunday.
>>
>> Michael Kay
>> http://www.saxonica.com/
>>
>> ------------------------------
>>
>> Date: Sun, 12 Apr 2009 19:52:19 +0000 (GMT)
>> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
>> From: Florent Georges <lists@xxxxxxxxxxxx>
>> Subject: Re : [xsl] How to handle dynamic XPath
>> Message-ID: <816269.32982.qm@xxxxxxxxxxxxxxxxxxxxxxxxxxx>
>>
>> fred@xxxxxxxxxxxxx wrote:
>>
>> B Hi,
>>
>>> <xsl:with-param name=3D"instance.path"
>>> select=3D"concat($instance.path,'/',$element.prefix,':',@name)"
>>> />
>>
>> B You cannot evaluate an XPath expression supplied as a string in plain
>> XSL=
>> T. B You can use extensions though for that purpose (of your own or
>> existing=
>> B one.) B I haven't looked deeply into your problem, but I'd say I'd
rather
>> u=
>> ser either:
>>
>> B 1/ maintaining a pointer in the instance and selecting its correct
>> child(=
>> ren) using local-name() and namespace-uri() for each step;
>>
>> B 2/ or using a meta-stylesheet: your stylesheet generates another XSLT
>> sty=
>> lesheet that contains the XPath expressions (you "compile" the schema to
>> th=
>> e equivalent stylesheet) and you apply this stylesheet to the instance in
>> a=
>> B second execution.
>>
>> B Regards,
>>
>> --=20
>> Florent Georges
>> http://www.fgeorges.org/
>>
>> =0A=0A=0A
>>
>> ------------------------------
>>
>> End of xsl-list Digest
>> ***********************************

Current Thread