xsl-list
[Top] [All Lists]

Re: empty elements to filled without overlapping hierachies

2003-11-13 05:29:51
Hi James,

<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">

except .in this context being whatever is in group-starting-with above?

Yes. Within the <xsl:for-each-group> instruction, the context item is
the first item in the group. If you're grouping starting with <SN>
elements, then the first item in the group will usually be an <SN>
element (the exception being the very first group, which might start
with something other than an <SN> element).

So "current-group() except ." selects the items in the current group
aside from the first one. I could just as easily have used:

  current-group()[position() > 1]

And it would probably have been better to do so. I don't know why I
didn't :)

          <xsl:choose>
            <xsl:when test="not(self::Q)">
              <xsl:copy-of select="." />
            </xsl:when>

So case 1 above, copy anything that isn't Q

Yes, almost: if the first item in the group isn't a <Q> element, then
copy it. Actually, this should be:

  <xsl:when test="not(self::Q)">
    <xsl:copy-of select="current-group()" />
  </xsl:when>

in case there's more than one node in that group (e.g. the <SN> starts
with more than one <SSD>).

            <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>

So case 2 above, close the Q before the last SSD - this is where
my real question is.  If I don't include <xsl:strip-space
elements="body" />> This doesn't work right so you get:
 <Q value="foo">blah blah blah
 <SSD value="blah"/></Q>
instead of
 <Q value="foo">blah blah blah
 </Q><SSD value="blah"/>
but I'm not confident about what that is.  Is it because the
original might have had something like:
 <Q value="foo"/>blah blah blah
 <SSD value="blah"/>
 [whitespacenode]

That's absolutely correct. Stripping the whitespace-only text nodes
with <xsl:strip-space> is the easiest way to get around the problem, I
thought. Otherwise things get pretty fiddly.

Is there simultaneously an easy way to add in additional markup for the
individual lines inside of Q? i.e. either: <l>blah</l> or blah<lb/>?
so:
 <Q value="foo"><l>blah blah blah</l>
 <l>blah blah blah blah blah</l>
 <l>blah blah blah blah blah</l><SSD value="foo"/>
 <l>blah blah blah blah blah</l></Q>
 <SSD value="blort"/>

Yes. Rather than using <xsl:copy-of> inside the newly-created <Q>
elements, apply templates to the nodes that will make up the content
of the <Q> elements. You want to copy the <SSD> elements:

<xsl:template match="SSD">
  <xsl:copy-of select="." />
</xsl:template>

then for the text nodes, you want to create <l> elements at each line
break. I think that the easiest way to do that is simply to break up
the value of the text node at line breaks using the tokenize()
function. You can then iterate over the substrings that you get to
create the <l> elements:

<xsl:template match="text()">
  <xsl:for-each select="tokenize(., '\n')">
    <l><xsl:value-of select="normalize-space(.)" /></l>
  </xsl:for-each>
</xsl:template>

Note that I normalized the space in each particular line, to get rid
of leading whitespace.

You could use <xsl:analyze-string> rather than the tokenize() function
if you prefer.

An XSLT 1.0 solution would be harder...

Yes, certainly. I'm assuming it isn't necessarily impossible? But
XSLT2 is fine with me ;-)

It would certainly be possible in XSLT 1.0, but it wouldn't be pretty
and maintenance would be a pig.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list