Odd behavior in XQuery comments

1.8k views Asked by At

I have a set of XQuery transformations that I am running on files stored in a Sedna database. They all have roughly the following format:

declare namespace ns0 = "http://www.someuri.com/foo.xsd";
declare namespace ns1 = "http://www.someuri.com/bar.xsd";

(:Declare a few functions like the following:)
declare function local:to-xs-boolean(
    $string as xs:string?
)
as xs:boolean? {
    if (fn:upper-case($string) = 'Y') then
        xs:boolean('true')
    else
        if (fn:upper-case($string) = 'N') then
            xs:boolean('false')
        (:if it isn't Y or N then attempt a normal cast - this will fail if it
        it isn't any of 'true', 'false', 1, or 0 :)
        else
            if ($string != '') then
                xs:boolean($string)
            else
                ()
        (:endif:)
    (:endif:)
};

(:Omitted several other functions:)

(:Start the main program:)

(: { :)
for $formName in /ns0:formName
return
        <ns1:newFormName>
            {
                let $address := $formName/ns0:Address
                return
                    <NewAddress>{
                        (:Omitted code and elements unrelated to this question:)
                    }</NewAddress>
            }
            (:Omitted code and elements unrelated to this question:)
        </ns1:newFormName>

Now here is my question. You see that line right above the 'for' that reads '(: { :)'? It should be a comment, but for some reason it is crucial to the proper function of my query. If I delete it completely (or remove the '{' from inside the comment) I get

SEDNA Message: ERROR XPDY0002
It is a dynamic error if evaluation of an expression relies on some part of the dynamic context that has not been assigned a value.

If I uncomment it (so the line just reads '{') I get

SEDNA Message: ERROR XPST0003
It is a static error if an expression is not a valid instance of the grammar defined in A.1 EBNF.
Details: at (393:1), syntax error, unexpected {
         at (798:33), syntax error, unexpected end of file, expecting "," or }

If I have it both uncommented and add a matching '}' to the end of the file I get

SEDNA Message: ERROR XPST0003
It is a static error if an expression is not a valid instance of the grammar defined in A.1 EBNF.
Details: at (393:1), syntax error, unexpected {

If I add other text to that comment (like '(:text foo bar baz() blah {:)') it will continue to work as long as I leave that '{' in there.

Has anybody ever seen this before or have any idea what might be causing it? It isn't really a crucial issue (I can just make sure I have '(:{:)' in all of my transformations), but it is really making me curious. So thanks for any help, or even just joining me in puzzlement.

Oh one other quick note - I don't know if it makes any difference, but I am running the query out of Java using Charles Foster's Sedna API (http://www.cfoster.net/sedna/)



Edit: Here is a different query that I just wrote which shows the same issue. This seems reproducable to me, but if it is syntax error related it could be just me reproducing the syntax error. I will leave the old one up as well so future viewers of this question aren't confused.

declare namespace ns0 = "http://www.someuri.com/InitialSchema.xsd";
declare namespace ns1 = "http://www.someuri.com/FinalSchema.xsd";

declare function local:to-address(
    $recipient as xs:string?,
    $line1 as xs:string?,
    $line2 as xs:string?,
    $line3 as xs:string?,
    $city as xs:string?,
    $provinceOrState as xs:string?,
    $country as xs:string?,
    $postalOrZIP as xs:string?
)
as element() {
    if (fn:upper-case($country) = 'CA' or fn:upper-case($country) = 'US') then
        if (fn:upper-case($country) = 'CA') then
            <CanadianAddress>
                <City>{ $city }</City>
                <Country>{ $country }</Country>
                <PostalCode>{ $postalOrZIP }</PostalCode>
                <Province>{ $provinceOrState }</Province>
                <Recipient>{ fn:normalize-space($recipient) }</Recipient>
                <StreetAddress>{ $line1 }</StreetAddress>
                <StreetAddress>{ $line2 }</StreetAddress>
                <StreetAddress>{ $line3 }</StreetAddress>
                <StreetAddress/>
            </CanadianAddress>
        else
            <USAddress>
                <City>{ $city }</City>
                <Country>{ $country }</Country>
                <ZipCode>{ $postalOrZIP }</ZipCode>
                <State>{ $provinceOrState }</State>
                <Recipient>{ fn:normalize-space($recipient) }</Recipient>
                <StreetAddress>{ $line1 }</StreetAddress>
                <StreetAddress>{ $line2 }</StreetAddress>
                <StreetAddress>{ $line3 }</StreetAddress>
            </USAddress>        
        (:endif:)
    else
        if ($country != '') then        
            <InternationalAddress>
                <City>{ $city }</City>
                <Country>{ $country }</Country>
                <PostalCode>{ $postalOrZIP }</PostalCode>
                <Recipient>{ fn:normalize-space($recipient) }</Recipient>
                <StreetAddress>{ $line1 }</StreetAddress>
                <StreetAddress>{ $line2 }</StreetAddress>
                <StreetAddress>{ $line3 }</StreetAddress>
            </InternationalAddress>
        else
            <CanadianAddress>
                <City>{ $city }</City>
                <Country>{ $country }</Country>
                <PostalCode>{ $postalOrZIP }</PostalCode>
                <Province>{ $provinceOrState }</Province>
                <Recipient>{ fn:normalize-space($recipient) }</Recipient>
                <StreetAddress>{ $line1 }</StreetAddress>
                <StreetAddress>{ $line2 }</StreetAddress>
                <StreetAddress>{ $line3 }</StreetAddress>
                <StreetAddress/>
            </CanadianAddress>
        (:endif:)
    (:endif:)
};


(:{:)
for $addressForm1 in /ns0:AddressForm
let $token := xs:integer(data($addressForm1/ns0:submissionID))
return
        <ns1:NewAddressForm>
            <SubmissionID>{ data($addressForm1/ns0:submissionID) }</SubmissionID>
            {
                let $currentAddress := $addressForm1/ns0:currentAddress
                return
                    <NewAddress>{
                        local:to-address(
                            concat(
                                $addressForm1/ns0:fullName/ns0:firstName,
                                ' ',
                                substring(data($addressForm1/ns0:fullName/ns0:middleName), 1, 1),
                                ' ',
                                $addressForm1/ns0:fullName/ns0:lastName
                            ),
                            data($currentAddress/ns0:line1),
                            data($currentAddress/ns0:line2),
                            data($currentAddress/ns0:line3),
                            data($currentAddress/ns0:city),
                            data($currentAddress/ns0:provinceOrState),
                            data($currentAddress/ns0:country),
                            data($currentAddress/ns0:postalOrZipCode)
                        )
                    }</NewAddress>
            }
        </ns1:NewAddressForm>

And here is some sample data for the new query

<?xml version="1.0"?>
<ns0:AddressForm xmlns:ns0="http://www.someuri.com/InitialSchema.xsd">
    <ns0:submissionID>23774</ns0:submissionID>
    <ns0:fullName>
        <ns0:firstName>First</ns0:firstName>
        <ns0:middleName>Middle</ns0:middleName>
        <ns0:lastName>Last</ns0:lastName>
    </ns0:fullName>
    <ns0:currentAddress>
        <ns0:line1>Line 1</ns0:line1>
        <ns0:line2>Line 2</ns0:line2>
        <ns0:line3>Line 3</ns0:line3>
        <ns0:city>City</ns0:city>
        <ns0:provinceOrState>Province</ns0:provinceOrState>
        <ns0:postalOrZipCode>H0H 0H0</ns0:postalOrZipCode>
        <ns0:country>CA</ns0:country>
    </ns0:currentAddress>
</ns0:AddressForm>

If it is a syntax error that is behind this would someone be so kind as to point out to me which line it is on?

1

There are 1 answers

0
Shcheklein On

The problem is the following line:

for $formName in /ns0:formName

In Sedna (remember Sedna is the database, not XQuery processor) there is no way to define default context item (see XQuery 1.0, 2.1.2 Dynamic Context) prior the query execution. So it doesn't know how to evaluate ./ns0:formName (which equivalent of simple /ns0:formName) - it just doesn't know what . means in this case.

You should load the document you want to process into the database and then access it with doc() function:

for $formName in doc('forms')/ns0:formName

As far as I know, you may also try Charles Fosters's XQJ API for Sedna (which should be anyway better than XML:DB API) which has support for defining context item.

BTW, if you have questions concerning Sedna's XML:DB or XQJ it's better to ask them directly in sedna-discussion list. There are very good chances that Charles will answer you.