xsl-list
[Top] [All Lists]

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

2009-04-13 09:51:19
Finished my reply too-soon.

Another major use of an XPath 2.0 parser could be in a refactoring
tool, and also adding to Mukuls Lint the so needed XPath expression
analysis.


-- 
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 Mon, Apr 13, 2009 at 6:46 AM, Dimitre Novatchev 
<dnovatchev(_at_)gmail(_dot_)com> wrote:
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(_at_)flowcanto(_dot_)com> 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(_at_)lists(_dot_)mulberrytech(_dot_)com
From: fred(_at_)flowcanto(_dot_)com
Subject: How to handle dynamic XPath
Message-ID: 
<20090412210729(_dot_)uv66b6hsw0sgksw0(_at_)webmail(_dot_)flowcanto(_dot_)com>

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)"=
 =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(_at_)lists(_dot_)mulberrytech(_dot_)com
From: "G. Ken Holman" <gkholman(_at_)CraneSoftwrights(_dot_)com>
Subject: Re: [xsl] How to handle dynamic XPath
Message-Id: 
<7(_dot_)0(_dot_)1(_dot_)0(_dot_)2(_dot_)20090412152437(_dot_)02699d30(_at_)wheresmymailserver(_dot_)com>

At 2009-04-12 21:07 +0200, fred(_at_)flowcanto(_dot_)com 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
 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.  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
 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.  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:

 <xsl:value-of select="document('file:/C:/dir/order.xml')/
                       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.  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>B1</b>
  <c>C1</c>
  <b>B2</b>
  <d>
    <e>E1</e>
  </d>
</a>
T:\ftemp>type fred-default.xml
<f:a xmlns:f="urn:x-fred">
  <f:b>def-B1</f:b>
  <f:c>def-C1</f:c>
  <f:b>def-B2</f:b>
  <f:d>
    <f:e>def-E1</f:e>
  </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>def-B1</b>
  <c>def-C1</c>
  <b>def-B2</b>
  <d>
    <e>def-E1</e>
  </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";
                xmlns:f="urn:x-fred"
                version="2.0">

<xsl:key name="paths" match="*" use="f:make-path(.)"/>

<!--walk the element tree-->
<xsl:template match="*">
  <xsl:param name="path"/>
  <!--determine the path to this element-->
  <xsl:variable name="this-path"
                select="concat($path,f:make-step(.))"/>
  <!--preserve the element structure-->
  <xsl:copy>
    <!--preserve any attributes-->
    <xsl:apply-templates select="@*"/>
    <!--replace the value when there are no element children-->
    <xsl:choose>
      <xsl:when test="not(*)">
        <!--at a leaf element-->
        <xsl:value-of select="document('fred-default.xml')/
                              key('paths',$this-path)"/>
      </xsl:when>
      <xsl:otherwise>
        <!--at a branch element, keep going-->
        <xsl:apply-templates>
          <xsl:with-param name="path" select="$this-path"/>
        </xsl:apply-templates>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:copy>
</xsl:template>

<!--identity for all other nodes-->
<xsl:template match="@*|comment()|processing-instruction()">
  <xsl:copy/>
</xsl:template>

<!--create a lookup key-->
<xsl:function name="f:make-path">
  <xsl:param name="element"/>
  <xsl:sequence select="string-join( for $e in
$element/ancestor-or-self::*
                                     return f:make-step( $e ), '' )"/>
</xsl:function>

<xsl:function name="f:make-step">
  <xsl:param name="element"/>
  <xsl:for-each select="$element">
    <xsl:sequence select="concat('/{',namespace-uri(.),'}',local-name(.),

 '[',count(preceding-sibling::*[node-name(.)=node-name(current())])+1,
       ']')"/>
  </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:    http://www.youtube.com/watch?v=PrNjJCh7Ppg&fmt=18
Video overview:  http://www.youtube.com/watch?v=VTiodiij6gE&fmt=18
G. Ken Holman                 
mailto:gkholman(_at_)CraneSoftwrights(_dot_)com
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/s/
Male Cancer Awareness Nov'07  http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal

------------------------------

Date: Sun, 12 Apr 2009 23:35:31 +0100
To: <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
From: "Michael Kay" <mike(_at_)saxonica(_dot_)com>
Subject: RE: [xsl] How to handle dynamic XPath
Message-ID: <4FA95E4459EE4A4B85EEF35A0C54B439(_at_)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(_at_)lists(_dot_)mulberrytech(_dot_)com
From: Florent Georges <lists(_at_)fgeorges(_dot_)org>
Subject: Re : [xsl] How to handle dynamic XPath
Message-ID: 
<816269(_dot_)32982(_dot_)qm(_at_)web23005(_dot_)mail(_dot_)ird(_dot_)yahoo(_dot_)com>

fred(_at_)flowcanto(_dot_)com wrote:

 Hi,

<xsl:with-param name=3D"instance.path"
select=3D"concat($instance.path,'/',$element.prefix,':',@name)"
/>

 You cannot evaluate an XPath expression supplied as a string in plain
XSL=
T.  You can use extensions though for that purpose (of your own or
existing=
 one.)  I haven't looked deeply into your problem, but I'd say I'd rather
u=
ser either:

 1/ maintaining a pointer in the instance and selecting its correct
child(=
ren) using local-name() and namespace-uri() for each step;

 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=
 second execution.

 Regards,

--=20
Florent Georges
http://www.fgeorges.org/

=0A=0A=0A

------------------------------

End of xsl-list Digest
***********************************




--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--




--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--