Split A Node If It Has Certain Children
Solution 1:
It looks like your input is a little bit inconsistent with your output. (Is that the expected output, or the output you're getting now)? Chunks a-02 and a-03 have no <highlight>
elements in the input, yet the output has <span class="highlight...">
elements. Also, chunk a-03 has text duplicated after the blockquote.
I believe I've produced a working solution that does everything in your example. Could you give this a try?
<xsl:stylesheetversion="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:outputmethod="xml"indent="yes"/><xsl:templatematch="/"><html><head><metahttp-equiv="Content-Type"content="text/html; charset=utf-8" /><title>Test</title></head><body><xsl:apply-templates/></body></html></xsl:template><xsl:templatematch="p | div"><xsl:variablename="breaks"select="note | pgBreak | quote" /><xsl:variablename="firstNonBreak"select="node()[count(. | $breaks) != count($breaks)][1]" /><xsl:variablename="nonBreaksAfterBreak"select="$breaks/following-sibling::node()[1][count(. | $breaks) != count($breaks)]" /><xsl:apply-templatesselect="$breaks | $firstNonBreak | $nonBreaksAfterBreak"mode="sectChild" /></xsl:template><!-- Template to output the chunk id attribute of a particular hierarchy --><xsl:templatename="ChunkId"><xsl:variablename="id"select="ancestor::*[../self::root]/@xml:id" /><xsl:iftest="$id"><xsl:attributename="data-chunkid"><xsl:value-ofselect="$id"/></xsl:attribute></xsl:if></xsl:template><!-- Splitting types - notes, page breaks, quotes --><xsl:templatematch="pgBreak"mode="sectChild"><divid="pg-{@pgId}"><xsl:value-ofselect="concat('Page ', @pgId)"/></div></xsl:template><xsl:templatematch="quote | note"mode="sectChild"><xsl:apply-templates /></xsl:template><!-- Receives the first node of each block of content outside of the splitting types
and passes processing onto itself and siblings within its block--><xsl:templatematch="text() | highlight | note.ref | super"mode="sectChild"><xsl:variablename="content"><xsl:apply-templatesselect="."mode="buildContent" /></xsl:variable><xsl:iftest="normalize-space($content)"><xsl:call-templatename="Nest"><xsl:with-paramname="hierarchy"select="ancestor::*[not(self::root)]" /><xsl:with-paramname="content"select="$content" /></xsl:call-template></xsl:if></xsl:template><!-- Recursive template to output nodes from the top level down to content --><xsl:templatename="Nest"><xsl:paramname="topLevel"select="true()"/><xsl:paramname="hierarchy" /><xsl:paramname="content" /><xsl:variablename="top"select="$hierarchy[1]" /><xsl:variablename="remainder"select="$hierarchy[position() > 1]" /><!-- If there's a quote or note yet to come, don't output tags until we get there --><xsl:variablename="skipTags"select="boolean($remainder[self::quote or self::note])" /><!-- Recursive output is captured in a variable, to be output later in this template --><xsl:variablename="inside"><xsl:iftest="$hierarchy"><xsl:call-templatename="Nest"><xsl:with-paramname="topLevel"select="$topLevel and $skipTags" /><xsl:with-paramname="hierarchy"select="$remainder" /><xsl:with-paramname="content"select="$content" /></xsl:call-template></xsl:if></xsl:variable><xsl:choose><xsl:whentest="not($hierarchy)"><xsl:copy-ofselect="$content" /></xsl:when><xsl:whentest="$top/self::quote"><blockquote><xsl:call-templatename="ChunkId" /><xsl:copy-ofselect="$inside"/></blockquote></xsl:when><xsl:whentest="$top/self::note"><divid="note-{$top/@id}"><xsl:call-templatename="ChunkId" /><xsl:copy-ofselect="$inside"/></div></xsl:when><xsl:whentest="not($skipTags)"><xsl:elementname="{name($top)}"><xsl:iftest="$topLevel"><xsl:call-templatename="ChunkId" /></xsl:if><xsl:copy-ofselect="$inside"/></xsl:element></xsl:when><xsl:otherwise><xsl:copy-ofselect="$inside"/></xsl:otherwise></xsl:choose></xsl:template><xsl:templatematch="node()"mode="buildContent"><xsl:iftest="not(self::note or self::quote or self::pgBreak)"><!-- output this node --><xsl:apply-templatesselect="self::node()[normalize-space(.)]"mode="contentOutput" /><!-- pass processing onto next sibling --><xsl:apply-templatesselect="following-sibling::node()[1]"mode="buildContent" /></xsl:if></xsl:template><!-- Bottom level content - text, note refs, superscript, highlight--><xsl:templatematch="text()"mode="contentOutput"><xsl:copy-ofselect="."/></xsl:template><xsl:templatematch="note.ref"mode="contentOutput"><spanclass="noteRef"id="{@id}"><xsl:apply-templatesmode="contentOutput"/></span></xsl:template><xsl:templatematch="super"mode="contentOutput"><sup><xsl:apply-templatesmode="contentOutput"/></sup></xsl:template><xsl:templatematch="highlight"mode="contentOutput"><xsl:variablename="class"select="concat(name(.),'-',string(@rend))"/><spanclass="{$class}"><xsl:apply-templatesmode="contentOutput"/></span></xsl:template></xsl:stylesheet>
I believe the unclosed meta tags is a result of using method="html"
. You may need to use method="xml"
to get closed meta tags. With method="html"
, the above transform produces the following output from your sample input:
<html><head><METAhttp-equiv="Content-Type"content="text/html; charset=utf-8"><title>Test</title></head><body><pdata-chunkid="a-01"><spanclass="highlight-italic">Bacon ipsum dolor sit amet</span> bacon chuck pastrami swine pork rump, shoulder beef ribs doner tri-tip
tongue. Tri-tip ground round short ribs capicola meatloaf shank drumstick short loin pastrami t-
bone. Sirloin turducken short ribs t-bone andouille strip steak pork loin corned beef hamburger
bacon filet mignon pork chop tail.
<spanclass="noteRef"id="0001"><sup>1</sup></span></p><divid="note-0001"data-chunkid="a-01"><p>
You may need to consult a <spanclass="highlight-italic">latin</span> butcher. Good Luck.
</p></div><pdata-chunkid="a-01">
Pork loin </p><divid="pg-01">Page 01</div><pdata-chunkid="a-01"> ribeye bacon pastrami drumstick sirloin, shoulder pig jowl. Salami brisket rump ham, tail
hamburger strip steak pig ham hock short ribs jerky shank beef spare ribs. Capicola short ribs swine
beef meatball jowl pork belly. Doner leberkas short ribs, flank chuck pancetta bresaola bacon ham
hock pork hamburger fatback.
</p><pdata-chunkid="a-02">
Bacon ipsum dolor sit amet bacon chuck pastrami swine pork rump, shoulder beef ribs doner tri-tip
tongue. Tri-tip ground round short ribs capicola meatloaf shank drumstick short loin pastrami t-
bone. Sirloin turducken short ribs t-bone andouille strip steak pork loin corned beef hamburger
bacon filet mignon pork chop tail.
</p><pdata-chunkid="a-03">
Bacon ipsum dolor sit amet bacon chuck pastrami swine pork rump, shoulder beef ribs doner tri-tip
tongue.
</p><blockquotedata-chunkid="a-03"><p>
Tri-tip ground round short ribs capicola meatloaf shank drumstick short loin pastrami t-
bone. Sirloin </p></blockquote><divid="pg-02">Page 02</div><blockquotedata-chunkid="a-03"><p>turducken short ribs t-bone andouille strip steak pork loin corned beef hamburger
bacon filet mignon pork chop tail.
</p></blockquote></body></html>
By changing the method to "xml" and manually adding the meta
element to the transform, you can obtain the same result, but with the following <head>
<head><metahttp-equiv="Content-Type"content="text/html; charset=utf-8" /><title>Test</title></head>
Post a Comment for "Split A Node If It Has Certain Children"