Metamark Wrapping: putting brackets around spanning markup

A project PI recently asked me the following XSLT question:

In my TEI I have the following markup:

A bunch of text and other various markup 

and then a

<metamark rend="red" spanTo="#meta-111"/>more text 
here<anchor xml:id="meta-111"/> and then 

the text continues, etc.

How do I wrap a bracket around the <metamark> to <anchor> pairing, and moreover how do I make it red?

That is, I want: … [more text here] … in my HTML output. Help!


This is actually fairly easy to do in XSLT if the encoding is consistent and you are only using metamark in this way (otherwise you should use the other attributes on metamark to delineate its function as well).

In this case the secret is to not think about wrapping the metamark/anchor pairing in square brackets but providing a starting square bracket and an ending square bracket through using two templates. We treat them as separate actions rather than trying to link them in any complicated way. (That is possible but much more difficult.)

 <xsl:template match="metamark
 [contains(@rend, 'red')]
 [substring-after(@spanTo, '#')= following::anchor/@xml:id]">
 <span class="metamark makeRed">[</span>
 <xsl:template match="anchor
 [contains(preceding::metamark/@spanTo, @xml:id)]">
 <span class="metamark makeRed">]</span>

In the first XSLT template we only match those metamarks where:

  • the @rend attribute contains ‘red’ and
  • the @spanTo attribute, once we have removed the ‘#’ on the front, equals any @xml:id that is on an anchor element following it. (This means there is one following it somewhere but we don’t need to know where. means there is one somewhere following it… it doesn’t necessarily have to be the next one.)

Then on the second template we match any anchor where:

  •  there is an @xml:id and
  • the @xml:id attribute on this anchor is pointed at by a metamark/@spanTo attribute that precedes it somewhere

We don’t need to have any real correspondence or connection between the two templates, and indeed if any of these accidentally fired on other metamarks or anchors, we could put in additional testing.

In both cases we put out an HTML span element with a bracket in it and given this span two classes ‘metamark’ and ‘makeRed’ to enable the project to control the styling of the metamark display and to colour things ‘red’.  i.e.

.metamark{font-size:80%; font-weight:bold;}


This is fairly straightforward and it is only a conceptual approach where those used to XML structures would often think about wrapping an element around something rather than just giving its starting and ending points in their output.

[UPDATE: As Torsten notes below, I don’t need to provide the namespace for these TEI elements because I have, sensibly, used @xpath-default-namespace and an @xmlns on the <xsl:stylesheet> element that you don’t see in these extracts.]

Posted in TEI, XML, XSLT | 2 Comments

2 Responses to “Metamark Wrapping: putting brackets around spanning markup”

  1. Torsten Schaßan says:

    Remember that you XPath expression works only if your TEI document doesn’t know that it is a TEI document because you haven’t used @xmlns or if you set the @xpath-default-namespace within .
    Otherwise your xsl:template/@match will not match anything, because it should be looking for tei:metamark[…]

  2. James Cummings says:

    Torsten: Yes, indeed. Why would anyone write XSLT processing TEI and not use @xpath-default-namespace? So yes, anyone reading this in the future should be aware of that assumption.

Leave a Reply