-
Notifications
You must be signed in to change notification settings - Fork 27
Introducing XSLT
We're introducing XSLT in oXygen with a simple Identity Transformation stylesheet, in which we make a few changes to an XML file. Later we'll be applying XSLT to change XML into other kinds of documents, including HTML for display on the web.
Have you done the following?
-
FIRST TIME in oXygen: Shut off outputting "default attribute values" :
- Go to Options -> Preferences -> XML -> XSLT-FO-XQuery (turn triangle) -> Saxon -> Saxon HE/PE/EE and make sure to DESELECT "Expand attribute defaults ("-expand"). (Leaving this selected makes some cluttered output.) Click the "Apply" and "OK" buttons at the bottom of the screen to apply the change.
-
Find and click on the tiny XSLT debugger button at top right of oXygen. The view changes to give you panels, for input (on left), XSLT processing (in middle), and output on right. (You might not see the output panel yet until you've run your first XSLT transformation.)
- Notice the "Select XML Source", the "XSL:" and "Output:" areas. You need the input and XSLT files you are processing to be selected here. If you have multiple XML and XSLT files open, the one visible is NOT necessarily the one you're running. What's running must always be selected in the boxes here.
- Underneath "Select XML Source", choose Saxon-PE (you could use Saxon-HE, Saxon-PE, or Saxon-EE for our work). These are the most up-to-date Saxon parsers, and we need them.
-
Open a new XSLT file (and adapt it as we direct in the first assignment). Namespaces matter here:
- We have an XSLT namespace, an xpath-default-namespace (for when our source XML has a namespace (like the TEI), and a namespace for the output if you need it.
- On the XSLT stylesheet, set the version number to 3.0 (we're using the latest features for this Identity transformation).
- Open our Georg Forster XML file (linked from XSLT Ex 1. This is our source file that we'll be changing.
- For an Identity Transformation stylesheet in version 3.0, set this self-closing element, as the first child of the XSLT root element:
<xsl:mode on-no-match="shallow-copy"/>
- Elements in XSLT usually create templates that match onto elements in the source XML. A template matches an XPath pattern (just exactly like the Schematron rule context). This is the name of a sequence of XML nodes that can appear anywhere in the XML hierarchy.
<xsl:template match="p">
</xsl:template>
XSL Templates nearly always open and close. What happens if there is nothing inside? Run the code to see what happens. To run, hit the blue arrow over on the right (which means "run to end"). The big blue button in the middle is usually okay, too. Inspect the output: what happened? Why did it happen?
Template rules basically match on an element and consume it--as in devour or ingest.
-
The usual code we put inside a template match element is an element that applies templates: It looks for other template rules to run on this element's children and children's children. . If it doesn't find them, it falls back on XSLT's default behavior, which is to spit out plain text. Because we're running in <xsl:mode on-no-match="shallow copy">, this LITERALLY means that when there are NO template rules present, any child node is to be copied from the source document.
-
Look at what happens when you do this:
<xsl:template match="p">
<xsl:apply-templates/>
</xsl:template>
What happens, and why? Consuming the match means XSLT has devoured the element tags and sent the child nodes (text and descendant elements) off to be processed by whatever OTHER template rules or modes are present in the XSLT.
- TO CHANGE something about the paragraph elements, but leave the element in place, PUT IT BACK:
<xsl:template match="p">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
NOTICE--we lost an attribute value! This was our @n attribute holding paragraph numbers! PUT THEM BACK with an Attribute Value Template:
<xsl:template match="p">
<p n="{@n}">
<xsl:apply-templates/>
</p>
</xsl:template>
What happens if you forget the curly braces? (Remove them and run the code to see.)
What if there weren't an @n to number the paragraphs in the first place? How did we do the auto-numbering?
The answer is, we used an XPath function that counts the preceding <p> elements and adds one more to it. We used the preceding:: axis because our paragraphs are at multiple levels of the XML hierarchy (some are children of the <div type="book">, and some are children of <div type="chapter">, some are children of <note> elements). It doesn't matter where the <p> elements are in the tree. The XSLT template match will find them wherever they are. Anything INSIDE the template rule is expressed as a literal XPath from the point of view of the template match element. So you count nodes on the preceding:: axis from the point of view of the current <p> being processed. Try it!