Tonya Howe
Tonya Howe

Reputation: 55

Rendering transforming XML elements inside other elements (XSLT, XQL and eXist-db)

I am trying to render a title page in xml, which I'm doing through an eXist-db app. Here is the relevant xml:

<front>
            <titlePage>
                <titlePart>
                    <lb>THE</lb>
                    <lb>ADVENTURES</lb>
                    <lb>OF</lb>
                    <lb>Roderick Random.</lb>
                    <lb><epigraph xml:lang="la">
                        <cit>
                            <quote xml:lang="la" link="http://www.perseus.tufts.edu/hopper/text?doc=Perseus%3Atext%3A1999.02.0062" title="Satires 2.5.8: 'But birth and virtue, unless [attended] with substance, is viler than seaweed.'">
                                <l>Et genus &amp; virtus, nisi cum re, vilior alga est.</l>
                            </quote>
                            <bibl>
                                <author ref="HOR" link="http://en.wikipedia.org/wiki/Horace" title="Quintus Horatius Flaccus, Roman lyric poet of the 1st century BCE">HOR.</author>
                            </bibl>
                        </cit>
                    </epigraph>
                    </lb>
                    <lb>IN TWO VOLUMES.</lb>
                    <lb>VOL. I.</lb>
                    <lb>THE TENTH EDITION.</lb>
                    <hr/>
                    <lb><name type="place">LONDON:</name></lb>
                    <lb>Printed for W. STRACHAN, J. RIVINGTON, R. BALDWIN, HAWES CLARKE, AND COLLINS, W. JOHNSTON, T. CASLON, B. LAW, J. JOHNSON AND Co, W. AND J. RICHARDSON, T. BECKETT, and P.. DeHONDT,</lb>
                    <lb><date title="1775">MDCCLXXV.</date></lb>
                </titlePart>
            </titlePage>
            <pb n="titlepage" facs="smollett.png"/>
        </front>

Graphically at this point, all I want is every <lb> on a separate line. I also want the <epigraph>s to appear wherever they do within the existing logic of the title page--that is, inline with the existing <lb>s. This screenshot should help make it clear: screenshot of flawed rendered page

Here are the relevant .xql bits with the xsl transformations. If you want to see all of the .xql, you can see that here (again, apologies for the true inelegance throughout): https://gist.github.com/tonyahowe/c55167e13ae22139f94080289cb88f47:

declare function tei2:tei2html($nodes as node()*) {
    for $node in $nodes
    return
        typeswitch ($node)
            case text() return
                $node
            case element(tei:TEI) return
                tei2:tei2html($node/*)
            case element(tei:teiHeader) return
                tei2:header($node) 
            case element(tei:frontTitle) return
                <h3>{ tei2:tei2html($node/node()) }</h3>
            case element(tei:lb) return
                <br>{ tei2:tei2html($node/node()) }</br>
            case element(tei:l) return
                <l>{ tei2:tei2html($node/node()) }</l>
            case element(tei:i) return
                <i>{ tei2:tei2html($node/node()) }</i>
            case element(tei:pb) return
                <span style="color:lightgray">[end page {tei2:tei2html($node/@n)}]{ tei2:tei2html($node/node()) }</span>
            case element(tei:footer) return
                <hr>{ tei2:tei2html($node/node()) }</hr>
            case element(tei:front) return
                tei2:front($node)
            case element(tei:rs) return 
                tei2:link($node)
            case element(tei:quote) return 
                tei2:link($node)
            case element(tei:note) return
               tei2:note($node) 
            case element(tei:footnote) return
                tei2:footnote($node)
            case element(tei:p) return
                <p xmlns="http://www.w3.org/1999/xhtml" id="{tei2:get-id($node)}">{ tei2:tei2html($node/node()) }</p> (: THIS IS WHERE THE ANCHORS ARE INSERTED! :)
            case element(exist:match) return
                <mark xmlns="http://www.w3.org/1999/xhtml">{ $node/node() }</mark>
            case element() return
                tei2:tei2html($node/node())
            default return
                $node/string() (: what would this catch? comment node in the xml? :)
};

declare function tei2:link($node as element()) {
  if ($node/@link ne '' and $node/@link castable as xs:anyURI) then 
    <a href="{$node/@link}" data-toggle="tooltip" title="{$node/@title}">{
      tei2:tei2html( $node/node() )
    }</a>
  else 
    tei2:tei2html( $node/node() )
};

declare function tei2:note($node as element()) {
    <span style="color:black" href="{$node/@link}" data-toggle="tooltip" title="{$node/@title}"> {
        tei2:tei2html ( $node/node() )
    }</span>
}; 

-------------------------- cut

declare function tei2:front($front as element (tei:front)) {
    let $titlePage := $front//tei:titlePage
    let $titlePart := $front//tei:titlePart
    let $epigraph := $front//tei:epigraph
    let $note := $front//tei:note
    let $argument := $front//tei:argument
    let $quote := $front//tei:quote
    let $bibl := $front//tei:bibl
    let $author := $front//tei:author
    
    return
        <div xmlns="http://www.w3.org/1999/xhtml" class="main-text-frontmatter">
        {   
            for $lb in $titlePage
            return 
                $titlePage//tei:lb
                
                    
            }
  
            {
                console:log($epigraph),
                for $cit in $epigraph
                return
                    <blockquote>
                        {
                            <a href="{$quote/@link}" data-toggle="tooltip" title="{$quote/@title}">{$quote/tei:l}</a>
                            
                        }<br/>

                        --
                            {
                                <a href="{$author/@link}" data-toggle="tooltip" title="{$author/@title}">{$author/text()}</a>
                            }
                    </blockquote>
            }
            </div>
};

Upvotes: 1

Views: 174

Answers (2)

wst
wst

Reputation: 11771

I don't see where you are transforming the lb elements into HTML:

for $lb in $titlePage
return 
    $titlePage//tei:lb

This will just dump out the TEI XML, which will be invalid HTML.

It looks like the tei2:tei2html function will render <lb>s correctly in HTML, but it will also render the <epigraph>s you want to exclude. If your XML is very predictable and similar to your example, you could exclude the <lb>s containing an epigraph using a predicate:

$titlePage//tei:lb[not(tei:epigraph)]

But that is fairly brittle and will also exclude <lb>s that contain <epigraph>s mixed with any text nodes you may want to preserve. In that case, you can recursively process the elements to remove them:

declare function local:remove-epigraph(
  $node as node()
) as node()*
{
  typeswitch ($node)
  case element(tei:epigraph) return ()
  case element() return element { node-name($node) } {
    for $n in $node/node()
    return local:remove-epigraph($node)
  }
  default return $node
};

...

$titlePage//tei:lb/local:remove-epigraph(.)

Update:

If you DO want to render the epigraph element inline, then simply use the tei2:tei2html function to render them:

$titlePage//tei:lb/tei2:tei2html(.)

Upvotes: 1

Joe Wicentowski
Joe Wicentowski

Reputation: 5294

Typically in TEI, the lb element is an empty, milestone element, so it only appears as: <lb/>. (See the TEI Guidelines on the lb element. It marks the place where a line break occurs, rather than surrounding the entire content of a line, as you have used it in the TEI here.

In the same way, HTML's <br/> element is an empty element. So your typeswitch for this element can turn into case element(tei:lb) return <br/>.

Adjusting your TEI markup to this <lb/> form, and adjusting your typeswitch to ourput HTML <br/> elements, may get you on the path to a solution.

Upvotes: 3

Related Questions