Newer
Older
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
version="1.0">
<xsl:output
method="xml"
indent="yes"
encoding="UTF-8"
standalone="yes"
/>
<xsl:template match="office:automatic-styles">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<!-- TODO: add styles for new sections based on the frames? -->
<!-- create a derived style for each paragraph we strip from around a frame,
which should be identical but for having a 0 line height -->
<xsl:for-each select="//text:p[draw:frame]
|//text:h[draw:frame]">
<xsl:element name="style:style">
<xsl:variable name="style-name" select="@text:style-name"/>
<xsl:attribute name="style:family">paragraph</xsl:attribute>
<xsl:attribute name="style:name">
<xsl:value-of select="concat('Placeholder', $style-name)"/>
</xsl:attribute>
<xsl:attribute name="style:parent-style-name">
<xsl:value-of select="$style-name"/>
</xsl:attribute>
<!-- copy the original style:master-page-name attribute -->
<xsl:copy-of select="//office:automatic-styles/style:style[@style:name=$style-name]/@style:master-page-name"/>
<xsl:element name="style:paragraph-properties">
<xsl:attribute name="fo:line-height">0</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!-- strip empty paragraphs that are likely here only to account for some
frame sizes and will increase the page contents size for no good reason
once the frames are stripped -->
<xsl:template match="text:p[count(*) = 0][count(preceding-sibling::*) > 0]">
<xsl:comment>Stripped empty <text:p text:style-name="<xsl:value-of select="@text:style-name"/>"></xsl:comment>
</xsl:template>
<!-- moves children of a draw:p containing a draw:frame outside of itself,
because we want to replace the frame with sections, which do not belong
inside a text:p -->
<xsl:template match="text:p[draw:frame] |
text:h[draw:frame]">
<xsl:comment>Removed outer <xsl:value-of select="name()"/></xsl:comment>
<!-- FIXME: there's probably a better way to do that -->
<xsl:for-each select="@*">
<xsl:choose>
<xsl:when test="../@text:style-name = .">
<xsl:attribute name="text:style-name">
<xsl:value-of select="concat('Placeholder', .)"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
<xsl:apply-templates/>
</xsl:template>
<!-- Detect frames we can't handle -->
<xsl:template match="draw:frame[count(draw:text-box) > 0 and count(draw:text-box) != count(*)]">
<xsl:message>Unsupported input with a frame combining children of different types</xsl:message>
<xsl:comment>Unsupported input with a frame combining children of different types</xsl:comment>
<xsl:call-template name="copy-and-recurse"/>
</xsl:template>
<!-- this is kind of a hack, as we stripped the text:p, we add it back -->
<xsl:template match="text:p/draw:frame[not(draw:text-box)]
|text:h/draw:frame[not(draw:text-box)]
|text:p[draw:frame]/*[not(self::draw:frame)][not(self::text:p)]
|text:h[draw:frame]/*[not(self::draw:frame)][not(self::text:h)]">
<xsl:comment>Re-added <xsl:value-of select="name(..)" /> wrapping element</xsl:comment>
<!-- FIXME: there's probably a better way to do that.
Here in order to change the context (and because XSLT 1.0 doesn't have
the "select" attribute on xsl:copy), we use a xsl:for-each that matches
a single element in order to switch context -->
<xsl:variable name="self" select="."/>
<xsl:for-each select="..">
<xsl:copy>
<!-- TODO: add the stripped p's attributes here (?) -->
<xsl:for-each select="$self">
<xsl:call-template name="copy-and-recurse"/>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
<!-- Replaces draw:frame/draw:text-box with a section -->
<xsl:template match="text:p/draw:frame[count(draw:text-box) = count(*)]
|text:h/draw:frame[count(draw:text-box) = count(*)]">
<xsl:comment>draw:text-box</xsl:comment>
<xsl:element name="text:section">
<xsl:attribute name="text:name">
<xsl:value-of select="concat('PlaceholderSection', count(preceding::*))" />
</xsl:attribute>
<xsl:apply-templates select="./draw:text-box/*"/>
</xsl:element>
<!-- companion for the above, catches frames not handled because outside of
supported elements. Should never happen, but helps debugging of unexpected
cases. -->
<xsl:template match="*[not(self::text:p) and not(self::text:h)][draw:frame[count(draw:text-box) = count(*)]]">
<xsl:message>Unsupported input with a draw:frame not inside a text:p or text:h (but a <xsl:value-of select="name()"/>) but with draw:text-box children</xsl:message>
<xsl:comment>Unsupported input with a draw:frame not inside a text:p or text:h (but a <xsl:value-of select="name()"/>) but with draw:text-box children</xsl:comment>
<xsl:call-template name="copy-and-recurse"/>
</xsl:template>
<!-- base template to match anything and call other templates -->
<xsl:template match="@* | node()" name="copy-and-recurse">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>