Phillip B Oldham
Phillip B Oldham

Reputation: 19385

XSL: Find text not currently in elements and wrap?

Given the following fragment:

<recipe>
  get a bowl
  <ingredient>flour</ingredient>
  <ingredient>milk</ingredient>
  mix it all together!
</recipe>

How can I match "get a bowl" and "mix it all together!" and wrap them in another element to create the following?

<recipe>
  <action>get a bowl</action>
  <ingredient>flour</ingredient>
  <ingredient>milk</ingredient>
  <action>mix it all together!</action>
</recipe>

Upvotes: 2

Views: 141

Answers (1)

Ian Roberts
Ian Roberts

Reputation: 122374

You could define a template matching text nodes that are a direct child of recipe:

<xsl:template match="recipe/text()">
  <action><xsl:value-of select="normalize-space()" /></action>
</xsl:template>

Full XSLT example:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:strip-space elements="*" />
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
  </xsl:template>

  <xsl:template match="recipe/text()">
    <action><xsl:value-of select="normalize-space()" /></action>
  </xsl:template>

</xsl:stylesheet>

Note that the normalize-space() is required, even with the xsl:strip-space - that only affects text nodes that contain only whitespace, it doesn't strip off leading and trailing space from nodes that contain any non-whitespace characters. If you had

<action><xsl:value-of select="." /></action>

then the result would be something like

<recipe>
  <action>
  get a bowl
  </action>
  <ingredient>flour</ingredient>
  <ingredient>milk</ingredient>
  <action>
  mix it all together!
</action>
</recipe>

Upvotes: 4

Related Questions