1
votes

I have an XML file with a series of pairings like the following:

<metamark function="let-stand" spanTo="#meta-93"/>some text between the two empty nodes<anchor xml:id="meta-93"/>

In other words, the text is always preceded with a metamark tag with @function='let-stand' and a spanTo with a unique value. And the text is always followed with an anchor tag whose @xml:id value match that of the @spanTo value on the metamark.

When transforming such text via XSLT into HTML, I would like to wrap it in a span tag as follows:

<span class="dotted">some text between the two empty nodes</span>

How can I achieve this? Note that the text between the two empty nodes will always be siblings. The value I've put on the span @class is arbitrary. I'm just using "dotted" for demonstration purposes here.

1
Please post a more substantial example (with several occurrences of such pairing shown in context), as well as the expected output. If there can be nesting, show that too.michael.hor257k

1 Answers

1
votes

The basic idea is that for each metamark:

  • create span tag,

  • get following siblings of the current metamark,

  • which as a following sibling have anchor tag with proper id (end point, exclusive),

  • and apply templates to them.

Of course, you have to block "normal" template application within the parent tag of your metamark tags.

Try the following transformation:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="html" doctype-public="XSLT-compat" 
    encoding="UTF-8" indent="yes" />

  <xsl:template match="metamark">
    <xsl:element name="span">
      <xsl:attribute name="class" select="'dotted'"/>
      <xsl:variable name="termId" select="substring(@spanTo, 2)"/>
      <xsl:variable name="srcRange" select="following-sibling::node()
        [following-sibling::anchor[@xml:id=$termId]]"/>
      <xsl:apply-templates select="$srcRange"/>
    </xsl:element>
    <xsl:text>&#xA;</xsl:text>
  </xsl:template>

  <!-- In "main" process only "metamark" tags -->
  <xsl:template match="main">
    <xsl:apply-templates select="metamark"/>
  </xsl:template>

  <!-- HTML envelope -->
  <xsl:template match="/">
    <html>
      <body>
        <xsl:text>&#xA;</xsl:text>
        <xsl:apply-templates />
      </body> 
    </html>
  </xsl:template>

  <!-- Identity transform -->
  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>

</xsl:transform>

I tried it for the following XML sample:

<?xml version="1.0" encoding="utf-8"?>
<main>
  <metamark function="let-stand" spanTo="#meta-93"/>Aaaaaa bbbbbbb<anchor xml:id="meta-93"/>
  <metamark function="let-stand" spanTo="#meta-94"/>Eeeeee <b>bbb</b> ccc<anchor xml:id="meta-94"/>
  <metamark function="let-stand" spanTo="#meta-95"/>Ffffff bbbbbbb<anchor xml:id="meta-95"/>
</main>

and got result:

<!DOCTYPE html PUBLIC "XSLT-compat">
<html>
   <body>
      <span class="dotted">Aaaaaa bbbbbbb</span>
      <span class="dotted">Eeeeee <b>bbb</b> ccc</span>
      <span class="dotted">Ffffff bbbbbbb</span>

   </body>
</html>