PDA

View Full Version : xmlpatterns issues or lack of understanding XQuery?



zaphod.b
6th January 2011, 14:32
Hi all,

this is gonna be somewhat longish - thx for your consideration.

I have written an XQuery that works fine in XMLSpy 2007 rel. 3 Enterprise (native Windows), but doesn't with xmlpatterns version 0.1 using Qt 4.7.1 (SLES-10) unless considerably tweaked. The question I have is: Are these issues of Qt xmlpatterns', or is it just my fault/lack of understanding? Also, should my solution be clumsy, please feel free to propose enhancements. :)

I should mention that I managed to work around these issues to reach my goal for the time being, yet the nature of this post is not purely academic.

I will first post the original query, then name the issues and tweaks. In the zip attached you will find the .xq file (containing both the original and the tweaked version) and the data it is meant to work on (actually an .xsd file edit: that I do not have control over).

The query should be executed like this (the last param is obsolete edit: until one wants to access a single attribute rather than the element sequence; see below):


xmlpatterns test.xq -param fileToOpen=CSBF_V_1_3.xsd -param dottedPath=Angebot.Bieter.ARGE_Mitglied.NUTS -param attrName=type

and it should return, in order, this sequence (abbreviated for clarity):


<xsd:element name="Angebot" .../>
<xsd:element name="Bieter" .../>
<xsd:element name="ARGE_Mitglied" .../>
<xsd:element name="NUTS" .../>

that is, the schema elements according to the "dottedPath" parameter.

This is the query that works in XMLSpy:


xquery version "1.0";

declare namespace csbf= "http://www.foo.de/csbf";
declare namespace xsd = "http://www.w3.org/2001/XMLSchema";
declare variable $fileToOpen as xs:anyURI external;
declare variable $inDoc as document-node() := doc($fileToOpen);
declare variable $dottedPath as xs:string external;
declare variable $attrName as xs:string external;

(:
This is ok for XMLSpy, but Qt xmlpatterns complains about the leading dot in
'let $e := ." (Error XPDY0002 [...] The focus is undefined.).
We therefore provide a variant to overcome this issue (see below).
:)
declare function csbf:schema-path($names as xs:string*) as element()*
{
if ( empty($names) )
then ()
else
let $e := .[last()]/child::xsd:sequence/child::xsd:element[@name=$names[1]]
let $complexTypeDef := $inDoc//xsd:complexType[@name=$e/@type/string()]
let $anchor := if ( exists($complexTypeDef ) )
then $complexTypeDef
else $e/xsd:complexType
return ( $e , $anchor/csbf:schema-path(subsequence($names, 2)) )
};

$inDoc//xsd:schema/xsd:element/xsd:complexType/csbf:schema-path(tokenize($dottedPath, '\.'))


The issues are:
(1) See function comment: Qt xmlpatterns doesn't set the context/focus dynamically and complains about the dot. I can work around this by adding another function parameter (see below).
(2) The resulting sequence is not in-order, but like this:


<xsd:element name="Angebot" .../>
<xsd:element name="ARGE_Mitglied" .../>
<xsd:element name="NUTS" .../>
<xsd:element name="Bieter" .../>

The element "Bieter" supposed to be second comes last. (Oops, can't [COLOR] inside
here?)
(3) (minor) xmlpattern warns that $attrName was not used. This can be worked around by adding
[CODE]
declare variable $attr as xs:string := $attrName;

and use that instead.

This is the tweaked query that works with both XMLSpy and xmlpatterns:
(edit: order is still incorrect, but workaround shown - see text below)


xquery version "1.0";

declare namespace csbf= "http://www.foo.de/csbf";
declare namespace xsd = "http://www.w3.org/2001/XMLSchema";
declare variable $fileToOpen as xs:anyURI external;
declare variable $inDoc as document-node() := doc($fileToOpen);
declare variable $dottedPath as xs:string external;
declare variable $attrName as xs:string external;

(:
Variant for Qt xmlpatterns compliance (see above).
:)
declare function csbf:schema-path($e as element(), $names as xs:string*) as element()*
{
if ( empty($names) )
then ()
else
let $e := $e/child::xsd:sequence/child::xsd:element[@name=$names[1]]
let $complexTypeDef := $inDoc//xsd:complexType[@name=$e/@type/string()]
let $anchor := if ( exists($complexTypeDef ) )
then $complexTypeDef
else $e/xsd:complexType
return ( $e , $anchor/csbf:schema-path($anchor, subsequence($names, 2)) )
(: return insert-before( $anchor/csbf:schema-path($anchor, subsequence($names, 2)), 1, $e ) :)
};

let $names := tokenize($dottedPath, '\.')
let $parent := $inDoc//xsd:schema/xsd:element/xsd:complexType
(:this returns the element sequence. comment out for attribute access.:)
return csbf:schema-path($parent, $names)

(:this returns the attribute value. uncomment as needed.:)
(:let $schema-element := $parent/csbf:schema-path($parent, tokenize($dottedPath, '\.'))[@name=$names[last()]]
return $schema-element/@*[name()=$attrName]/string():)


Since for now I need only access the cardinality, and the "dottedPath" tokens are presumably distinct, I can work around the second issue as shown in the above code (currently commented) accessing the element by name. However, this is not robust, and the assumption may fail in the future.

Any enlightenment is very much appreciated! :)

wysota
7th January 2011, 15:24
You should check your query against some reference implementation of XQuery to be sure whether it is Qt's version that is wrong or maybe the one in XMLSpy. Qt's implementation is certainly incomplete so I wouldn't be suprised if it didn't handle some of the special or rare situations.