Search code examples
htmlxmlxsltxquerytei

Is there a way to have an Xquery in an XSLT stylesheet which will be executed upon transformation?


I have an XML file which I've been trying to transform both with xQuery and XSLT at the same moment.

The document basically encodes two different types of text according to TEI standards. The first part is a philological study which I have written about an epic poem, and the second part is a scholarly edition of said poem.

<text>
<front><!-- chapters of the study --></front>
<body>
<lg n="1">
<l n="1.a">first line of the poem</l>
<l n="1.a">second line with <distinct>interesting stuff</distinct></l></lg>
<!-- rest of the poem-->
</body></text>

My main goal is to transform this with XSLT into a nicely formatted html document, and for the most part it works. Now, the study discusses data from the edition ("This interesting stuff occurs quite often in our poem, as is shown in the following table"). Since all the "interesting stuff" is marked up (see example above), I can easily create those tables using a combination of HTML and xQuery:

<table>
<tr>
<td>Verse Number</td>
<td>Interesting Stuff</td>
<tr>
for $case in doc("mydocument.xml")//distinct
return
<tr>
<td>{data($case/ancestor::l/@n)}</td>
<td>$case</td></tr></table>

The easy way at the moment would be to change the xQuery so it will create a TEI-conform xml table and copy that manually into the document. Then, the XSLT will work smoothly, just as it does for the few static tables that I have. But most of my tables should be dynamic, I want the numbers to change if I change something in the edition. This should be done every time a new reader opens the formatted text in the browser (i.e., each time the XSLT transformation is executed).

I tried combining the code as follows:

<xsl:template match="table[type='query']">
{ (: the xQuery-html instructions from above go here :) }
</xsl template>

I creates a table at the right place, but before it and in the cells it just repeats the xQuery instructions. I've been looking for similar questions, but I found only the reverse process, i.e. how to use xQuery to create XSLT (for example this: calling XQuery from XSLT, building XSLT dynamically in XQuery?), which does not help my problem.

Is there a way to combine the two codes?

Thanks in advance for your help!


Solution

  • There are various ways you can combine XSLT and XQuery. You can have XSLT tasks and XQuery tasks in the same pipeline, or you can invoke XQuery functions from XSLT (for example using load-xquery-module() in XSLT 3.0). But for the case you're describing, it's simplest to just replace the FLWOR expression with an equivalent xsl:for each:

    <xsl:for-each select='doc("mydocument.xml")//distinct'>
      <xsl:variable name="case" select="."/>
      <tr>
        <td>{$case/ancestor::l/@n}</td>
        <td>{$case}</td>
      </tr>
    </xsl:for-each>
    

    Note: XSLT 3.0 allows the curly-brace syntax (you need to specify expand-text="yes") but the semantics are slightly different from XQuery - it means "value-of" rather than "copy-of".