Reputation: 484
I have an XML document that I would like to convert to HTML. I am using Xquery with Oxygen parser for this.
This is the xml:
<?xml version="1.0" encoding="UTF-8"?>
<?oxygen RNGSchema="file:textbook.rnc" type="compact"?>
<books xmlns="books">
<book ISBN="i0321165810" publishername="OReilly">
<title>XPath</title>
<author>
<name>
<fname>Priscilla</fname>
<lname>Warnley</lname>
</name>
<address>
<street_address>Hill Park<street_address>
<zip>90210</zip>
<state>california</state>
</address>
<phone>00000000</phone>
<e-mail>[email protected]</e-mail>
</author>
<year>2007</year>
<field>Databases</field>
<TOC>
<component>
<type>Part</type>
<title>Xpath</title>
<component>
<title>Chapter... A tour of xquery</title>
<pages>3</pages>
<component>
<title>Introductions</title>
</component>
<component>
<title>Getting started</title>
</component>
</component>
</component>
</TOC>
</book>
<publisher publishername="OReilly">
<web-site>www.oreilly.com</web-site>
<address>
<street_address>hill park</street_address>
<zip>90210</zip>
<state>california</state>
</address>
<phone>400400400</phone>
<e-mail>[email protected]</e-mail>
<contact>
<field>Databases</field>
<name>
<fname>Anna</fname>
<lname>Smith</lname>
</name>
</contact>
</publisher>
</books>
I first do this Xquery query:
declare default element namespace "books";
<html>
<head>
<title>Table of contents</title>
</head>
<body>
<b>Table of contents</b>
<hr/>
{ for $i in //book[@ISBN='i0321165810']/TOC
return $i
}
</body>
</html>
based on my xml document get these results:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="Books">
<head>
<title>Table of content</title>
</head>
<body>
<b>TOC</b>
<hr/>
<TOC>
<component>
<type>Part</type>
<title>Foundations</title>
<component>
<title>Chapter... A tour of xquery</title>
<pages>3</pages>
<component>
<title>Introductions</title>
</component>
<component>
<title>Getting started</title>
</component>
</component>
</component>
</TOC>
</body>
</html>
What I would like to do now is replace the component tag with a pre tag (using spaces for indentation), the title tag with an italics tag and the pages tag with a bold tag (basically use HTML tags instead of XML tags, so the document can be viewed in a web browser). I tried to use the replace function, but I could not get it to work.
Could someone please help?
Upvotes: 2
Views: 1574
Reputation: 4241
As DevNull noted, this is a task where XSLT would shine. Here's my go at an XQuery solution:
declare default element namespace "http://www.w3.org/1999/xhtml";
declare function local:rename($node) {
let $old-name := local-name($node)
let $new-name :=
switch($old-name)
case 'component' return 'pre'
case 'title' return 'i'
case 'pages' return 'b'
default return $old-name
return element { $new-name } {
$node/@*,
for $nd in $node/child::node()
return if($nd instance of element())
then local:rename($nd)
else $nd
}
};
<html>
<head>
<title>Table of contents</title>
</head>
<body>
<b>Table of contents</b>
<hr/>
{ for $i in //*:book[@ISBN='i0321165810']/*:TOC/*
return local:rename($i)
}
</body>
</html>
The function local:rename($node)
recursively descends into the XML fragment, rebuilding it and substituting element names. It's neither very elegant nor efficient, but it should do the job.
I also changed the default element namespace
, as your returned XHTML document was in the books
namespace.
Upvotes: 5
Reputation: 6229
One straight-forward way (using XQuery Update) looks as follows:
declare default element namespace "books";
<html>
<head>
<title>Table of contents</title>
</head>
<body>
<b>Table of contents</b>
<hr/> {
copy $c := //book[@ISBN='i0321165810']/TOC
modify (
for $n in $c//component return rename node $n as 'tab',
for $n in $c//title return rename node $n as 'i',
for $n in $c//pages return rename node $n as 'b'
)
return $c
}</body>
</html>
Hope this helps, Christian
Upvotes: 3