Skip to content

Instantly share code, notes, and snippets.

@grtjn
Created April 18, 2012 07:47
Show Gist options
  • Save grtjn/2411825 to your computer and use it in GitHub Desktop.
Save grtjn/2411825 to your computer and use it in GitHub Desktop.
Dividing title and sub-title on colon inside inlines
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all">
<!--+
| Output specs
+-->
<xsl:output method="xml" encoding="UTF-8" indent="no" omit-xml-declaration="yes"/>
<xsl:preserve-space elements="*" />
<!--+
| Default (identity) template
+-->
<xsl:template match="@*|node()" mode="#all" priority="-1">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="#current" />
</xsl:copy>
</xsl:template>
<!--+
| Root template
+-->
<xsl:template match="/">
<xsl:variable name="marked-colons">
<xsl:apply-templates select="/" mode="mark-colons"/>
</xsl:variable>
<xsl:variable name="propagated-colons">
<xsl:apply-templates select="$marked-colons" mode="propagate-colons"/>
</xsl:variable>
<xsl:apply-templates select="$propagated-colons" mode="make-titles"/>
</xsl:template>
<!--+
| Mark colons
+-->
<xsl:template match="*" mode="mark-colons">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:for-each select="node()">
<xsl:choose>
<xsl:when test="self::text()[contains(., ': ')]">
<xsl:message>Marking colon in "<xsl:value-of select="."/>"</xsl:message>
<xsl:for-each select="tokenize(., ': ')">
<xsl:value-of select="."/>
<xsl:if test="not(position() = last())">
<colon/>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="#current" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!--+
| Propagate colons
+-->
<!-- Split parent element to propagate colon element up in hierarchy. Do so until reaching root element. -->
<xsl:template match="/" mode="propagate-colons">
<xsl:variable name="propagated-colons">
<xsl:apply-templates select="*" mode="propagate-colons"/>
</xsl:variable>
<xsl:choose>
<!-- check whether there are colons on non-root element level, recurse if so -->
<xsl:when test="exists($propagated-colons/*/*//colon)">
<xsl:message>Recursing propagate colons</xsl:message>
<xsl:apply-templates select="$propagated-colons" mode="propagate-colons"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$propagated-colons/*"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*/*[colon]" mode="propagate-colons">
<xsl:message>Splitting <xsl:value-of select="name(.)"/> to propagate colon upwards</xsl:message>
<xsl:for-each-group select="node()" group-starting-with="colon">
<!-- move colons upwards one parent at a time -->
<xsl:copy-of select="self::colon" />
<xsl:element name="{name(..)}" namespace="{namespace-uri(..)}">
<xsl:copy-of select="../@*" />
<xsl:apply-templates select="current-group()[not(self::colon)]" mode="propagate-colons"/>
</xsl:element>
</xsl:for-each-group>
</xsl:template>
<!--+
| Make titles
+-->
<xsl:template match="/*[colon]" mode="make-titles">
<xsl:variable name="parent" select="."/>
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:for-each-group select="node()" group-starting-with="colon">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:element name="title" namespace="{namespace-uri($parent)}">
<xsl:apply-templates select="current-group()[not(self::colon)]" mode="copy"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="sub-title" namespace="{namespace-uri($parent)}">
<xsl:apply-templates select="current-group()[not(self::colon)]" mode="copy"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment