Hi James,
What I'm wondering is what sort of strategy one could use in
XSLT (including XSLT2) to change these to filled tags. e.g.:
<Q value="WELBORNE." > NO BOUZE? NOR NO TOBACCO?</Q>
Let's try to find an XSLT 2.0 solution. It will use
<xsl:for-each-group> with the group-starting-with option, which groups
together items such that each group starts with the same thing.
When we match the <body> element, we want to copy it and its <TITLE>
child:
<xsl:template match="body">
<body>
<xsl:copy-of select="TITLE" />
...
</body>
</xsl:template>
The first level of grouping is <SN>s. We want to group all the
child nodes of the <body> element, aside from the <TITLE> element,
into groups that start with a particular <SN> element. For each of
these groups, we want to create a <SN> element with the value
attribute from the original <SN>:
<xsl:template match="body">
<body>
<xsl:copy-of select="TITLE" />
<xsl:for-each-group select="node() except TITLE"
group-starting-with="SN">
<SN value="{(_at_)value}">
...
</SN>
</xsl:for-each-group>
</body>
</xsl:template>
Next, we want to take the elements in that group (aside from the <SN>
element itself) and group them into groups starting with <Q> elements.
Now, there are three possible arrangements of these groups:
1. The very first group might not start with a <Q> element; in that
case, we just want to copy all the items in that group.
2. The group might end with a <SSD> element, in which case we want
to have a <Q> element that contains all the items in the group
aside from that final <SSD> element (and the <Q> element itself).
3. The group might end with something other than a <SSD> element, in
which case we want to have a <Q> element that contains all the
items in the group aside from the <Q> element itself
<xsl:template match="body">
<body>
<xsl:copy-of select="TITLE" />
<xsl:for-each-group select="node() except TITLE"
group-starting-with="SN">
<SN value="{(_at_)value}">
<xsl:for-each-group select="current-group() except ."
group-starting-with="Q">
<xsl:choose>
<xsl:when test="not(self::Q)">
<xsl:copy-of select="." />
</xsl:when>
<xsl:when test="current-group()[last()][self::SSD]">
<Q value="{(_at_)value}">
<xsl:copy-of select="(current-group() except .)
[position() != last()]" />
</Q>
<xsl:copy-of select="current-group()[last()]" />
</xsl:when>
<xsl:otherwise>
<Q value="{(_at_)value}">
<xsl:copy-of select="current-group() except ." />
</Q>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</SN>
</xsl:for-each-group>
</body>
</xsl:template>
This assumes that whitespace-only text nodes have been stripped from
the input tree using:
<xsl:strip-space elements="body" />
and the output looks best if you then include:
<xsl:output indent="yes" />
An XSLT 1.0 solution would be harder...
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list