How to prevent line-wrapping by XSLT?
I have some XML like this:
<root>
<do-not-sort>
<z/>
<y/>
</do-not-sort>
<sortable>
<e f="fog" h="bat" j="cat">
<n n="p"/>
<m n="p"/>
</e>
<d b="fop" c="bar" k="cab">
<m o="p"/>
<m n="p"/>
</d>
</sortable>
</root>
I want to sort the children of the "sortable" element by their textual representation, to end up with this:
<root>
<do-not-sort>
<z/>
<y/>
</do-not-sort>
<sortable>
<d b="fop" c="bar" k="cab">
<m n="p"/>
<m o="p"/>
</d>
<e f="fog" h="bat" j="cat">
<m n="p"/>
<n n="p"/>
</e>
</sortable>
</root>
I am currently doing this by applying the following XSLT template:
<?x开发者_StackOverflow中文版ml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="UTF-8" />
<xsl:template match="@* | /">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:value-of select="normalize-space(text()[1])" />
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sortable//*">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:value-of select="normalize-space(text()[1])" />
<xsl:apply-templates select="*">
<xsl:sort data-type="text" select="local-name()" />
<xsl:sort data-type="text" select="@*" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The sorting works correctly, but if the sorted elements have a lot of attributes, the later attributes each wrap onto a new line, for example:
<sortable>
<this is="an" element="with" a="lot" of="attributes"
and="the"
excess="ones"
each="wrap"
onto="their"
own="line"/>
How do I keep all these attributes on the same line, i.e.
<sortable>
<this is="an" element="with" a="lot" of="attributes" and="the" excess="ones" each="wrap" onto="their" own="line"/>
How do I keep all these attributes on the same line
In your code, replace:
<xsl:output method="xml" indent="yes" encoding="UTF-8" />
with
<xsl:output method="xml" encoding="UTF-8" />
Of course, this will produce the complete output on a single line! At the moment of writing this XSLT 2.0 still doesn't have a finer grained control over the serialization of the output.
In case you need some elements indented and some not, then you will have to provide your own post-processing (and this post-processing may be easier to write with something different from XSLT).
Update:
Actually, using Saxon 9.1.07 and
<xsl:output method="html" encoding="UTF-8" />
where the complete transformation is:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" />
<xsl:template match="@* | /">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:value-of select="normalize-space(text()[1])" />
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sortable//*">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:value-of select="normalize-space(text()[1])" />
<xsl:apply-templates select="*">
<xsl:sort data-type="text" select="local-name()" />
<xsl:sort data-type="text" select="@*" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
and the source XML document is:
<root>
<do-not-sort>
<z></z>
<y></y>
</do-not-sort>
<sortable>
<this is="an" element="with" a="lot" of="attributes" and="the" excess="ones" each="wrap" onto="their" own="line"></this>
<e f="fog" h="bat" j="cat"></e>
<d b="fop" c="bar" k="cab"></d>
<d b="foo" c="baz" k="cap"></d>
</sortable>
</root>
I get the output with the wanted indentation:
<root>
<do-not-sort>
<z></z>
<y></y>
</do-not-sort>
<sortable>
<this is="an" element="with" a="lot" of="attributes" and="the" excess="ones" each="wrap" onto="their" own="line"></this>
<e f="fog" h="bat" j="cat"></e>
<d b="fop" c="bar" k="cab"></d>
<d b="foo" c="baz" k="cap"></d>
</sortable>
</root>
If you are using Saxon, and want to avoid everything being on one line, you can use the 'line-length' attribute, like this:
<xsl:output xmlns:saxon="http://saxon.sf.net/" indent="yes" saxon:line-length="2000"/
However, be aware that this only works on the Saxon PE (Professional) edition. See here for details: http://www.saxonica.com/products/products.xml
If you are using the HE (Home) version, you will get an error like this:
Transformation failed: Requested feature (custom serialization {http://saxon.sf.net/}line-length) requires Saxon-PE
精彩评论