How can I fix ugly XQuery output?
Here is my XML document:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="student.xsl"?>
<Students xmlns="www.example.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="www.example.com student.xsd">
<Student>
<SSN>622-12-5748</SSN>
<Name>
<First-Name>Alexander</First-Name>
<Last-Name>Mart</Last-Name>
</Name>
<Age>26</Age>
<Institution>UCSF</Institution>
<Email>Alexander@yahoo.com</Email>
</Student>
</Students>
I have this XQuery:
xquery version "1.0";
declare namespace xsd开发者_运维问答 = "http://www.w3.org/2001/XMLSchema";
declare namespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
declare default element namespace "http://www.example.com";
for $s in doc("student.xml")/Students/Student
let $firstName := $s/First-Name
let $lastName := $s/Last-Name
let $email := $s/Email
order by $lastName ascending
return
<row>
<first-name> { $firstName } </first-name>
<last-name> { $lastName } </last-name>
<email> { $email } </email>
</row>
The output I am getting is:
<row xmlns="http://www.example.com">
<first-name>
<First-Name xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>Alexander</First-Name>
</first-name>
<last-name>
<Last-Name xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>Mart</Last-Name>
</last-name>
<email>
<Email xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>Alexander@yahoo.com</Email>
</email>
</row>
All the examples I see, though, output something like this:
<row>
<first-name>Alexander</first-name>
<last-name>Mart</last-name>
<email>Alexander@yahoo.com</email>
</row>
How do I format my output prettily like this?
Also, why am I getting this
<First-Name xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
tag in my results, instead of just <first-name>
? Is there a way to get rid of that? I added the declare default element namespace "http://www.example.com";
near the top because I couldn't get my XQuery to work without it. But it would be really nice if that wasn't getting displayed in my results.
Use:
declare namespace x = "http://www.example.com";
for $s in /x:Students/x:Student
let $firstName := $s/x:First-Name/text()
let $lastName := $s/x:Last-Name/text()
let $email := $s/x:Email/text()
order by $lastName ascending
return
<row>
<first-name> { $firstName } </first-name>
<last-name> { $lastName } </last-name>
<email> { $email } </email>
</row>
when this is applied to the following XML document (no XML document was provided by you!!!):
<Students xmlns="http://www.example.com">
<Student>
<First-Name>A</First-Name>
<Last-Name>Z</Last-Name>
<Email>A.Z@T.com</Email>
</Student>
</Students>
the wanted result is produced:
<row>
<first-name>A</first-name>
<last-name>Z</last-name>
<email>A.Z@T.com</email>
</row>
Explanation: The literal result elements (row
, etc.) are in the default element namespace. The solution is not to use default element namespace declaration.
XQuery 1.0 does not have a standard way to request indentation (or other formatting) of results. Many XQuery implementations have their own mechanisms. For example, if you're using Saxon from the command line, you can use the option !indent=yes. I don't know what options XMLSpy provides.
There is an XQuery 1.0 option "declare boundary-space preserve" which causes whitespace in the query to be copied to the output; this might have the effect you require, though in my experience it can also have unwanted effects.
First, your exact query shouldn't be producing that output. You must be using this instead (because of the default namespace declaration on your input):
declare namespace xsd = "http://www.w3.org/2001/XMLSchema";
declare namespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
declare namespace x = "www.example.com";
declare default element namespace "http://www.example.com";
for $s in /x:Students/x:Student
let $firstName := $s/x:Name/x:First-Name
let $lastName := $s/x:Name/x:Last-Name
let $email := $s/x:Email
order by $lastName ascending
return
<row>
<first-name> { $firstName } </first-name>
<last-name> { $lastName } </last-name>
<email> { $email } </email>
</row>
That indeed output:
<row xmlns="http://www.example.com">
<first-name>
<First-Name xmlns="www.example.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>Alexander</First-Name>
</first-name>
<last-name>
<Last-Name xmlns="www.example.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>Mart</Last-Name>
</last-name>
<email>
<Email xmlns="www.example.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>Alexander@yahoo.com</Email>
</email>
</row>
WHY?: Because your sequence constructor { $firstName }
output the node instace referenciated by $firstName
not its string-value. That should be:
declare namespace x = "www.example.com";
declare default element namespace "http://www.example.com";
for $s in /x:Students/x:Student
let $firstName := $s/x:Name/x:First-Name
let $lastName := $s/x:Name/x:Last-Name
let $email := $s/x:Email
order by $lastName ascending
return
<row>
<first-name> { $firstName/string() } </first-name>
<last-name> { string($lastName) } </last-name>
<email> { normalize-space($email) } </email>
</row>
Output:
<row xmlns="http://www.example.com">
<first-name>Alexander</first-name>
<last-name>Mart</last-name>
<email>Alexander@yahoo.com</email>
</row>
精彩评论