XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Generating XML and HTML using XQuery
by Per Bothner | Pages: 1, 2, 3, 4, 5, 6

Transforming DocBook to HTML using XQuery

Listing 4 is an XQuery program for doing the same DocBook-to-HTML translation. Since XQuery doesn't have XSLT's template-matching driver, we have to write explicit control flow using recursive function calls. The typeswitch expression is useful for selecting between different node types, but unfortunately XQuery type expressions are not as expressive as XPath patterns, so more complex patterns may need explicit logic.

Note especially how context patterns like artheader/title are handled. The idea is that in place of the XSLT rules that use the artheader context, we use a convert-artheader function.

An alternative method for handling context is to pass it as an explicit parameter like the $level parameter of convert-title.

Listing 4: An XQuery program to transform DocBook to HTML

define function convert-children ($x) {
  for $y in $x/node() return convert-node($y)
}

define function convert-title($x, $level) {
  if ($level <= 1) then <h1 class="title">{$x/node()}</h1>
  else if ($level = 2) then <h2 class="title">{$x/node()}</h2>
  else if ($level = 3) then <h3 class="title">{$x/node()}</h3>
  else if ($level = 4) then <h4 class="title">{$x/node()}</h4>
  else if ($level = 5) then <h5 class="title">{$x/node()}</h5>
  else <h6 class="title">{$x/node()}</h6>
}

define function convert-div-children ($x, $level) {
  for $y in $x/node() return
    typeswitch ($y)
      case element title return convert-title($y, $level)
      default return convert-node($y)
}

define function convert-artheader ($x) {
  for $y in $x/node() return
    typeswitch ($y)
      case element title return <h1>{convert-children($y)}</h1>
      case element subtitle return <h2>{convert-children($y)}</h2>
      case element authorgroup return <h3><i>{convert-children($y)}</i></h3>
      default return ( )
}

define function convert-biblioentry ($x) {
  for $y in $x/node() return
    typeswitch ($y)
      case element abbrev return ('[',convert-children($y),']')
      case element title return (<cite>{convert-children($y)}</cite>,'.')
      case element authorgroup return (convert-node($y),'.')
      default return convert-node($y)
}

define function convert-node ($x) {
  typeswitch ($x)
    case element article return <html>{convert-children($x)}</html>
    case element artheader return convert-artheader($x)
    case element title return <title>{convert-children($x)}</title>
    case element authorgroup return convert-children($x)
    case element author return convert-children($x)
    case element abstract return
     <div type='abstract'><h3>Abstract</h3>{convert-children($x)}</div>
    case element para return <p>{convert-children($x)}</p>
    case element screenshot return
      <img src="{string($x/mediaobject/imageobject/imagedata[@format="PNG"]/@fileref)}" />
    case element caption return <p><b>{convert-children($x)}</b></p>
    case element emphasis return <em>{convert-children($x)}</em>
    case element citation return ('[',convert-children($x),']')
    case element quote return ('"',convert-children($x),'"')
    case element classname return <code>{convert-children($x)}</code>
    case element function return <code>{convert-children($x)}</code>
    case element itemizedlist return <ul>{convert-children($x)}</ul>
    case element listitem return <li>{convert-children($x)}</li>
    case element sect1 return <div class="sect1">{convert-div-children($x, 2)}</div>
    case element sect2 return <div class="sect2">{convert-div-children($x, 3)}</div>
    case element programlisting return <pre>{convert-children($x)}</pre>
    case element informalfigure return convert-children($x)
    case element bibliography return
      <div class="bibliography"><h2>Bibliography</h2>{convert-children($x)}</div>
    case element biblioentry return <p>{convert-biblioentry($x)}</p>
    case element firstname return convert-children($x)
    case element surname return convert-children($x)
    default return ($x)
}

let $doc := input()
let $artheader := $doc/article/artheader
let $title := $artheader/title
return
<html>
<head>
{if ($title) then <title>{convert-children($title)}</title> else ()}
</head>
<body>
{convert-children($doc)}
</body>
</html>

These two stylesheets are of comparable size and complexity. The XSLT contains slightly fewer characters (2731 versus 3431), but the difference is minor, and this is the kind of application that is XSLT's strength. So my advice is, if you have a task that matches XSLT's strength, by all means use XSLT. However, if you have a task that is a mix of XSLT-style transformation combined with some control logic, consider using XQuery, even for the part of the task that is XSLT-like. The advantage of XSLT over XQuery in applications best suited for XSLT is relatively minor, while the pain of writing more complex logic in XSLT instead of XQuery is considerable. The photo album is an application I first wrote in XSLT, but I was able to easily make significant improvements when I rewrote it in XQuery.



1 to 1 of 1
  1. Good comparison examples
    2003-01-06 22:58:11 Ivelin Ivanov
1 to 1 of 1