11

How can I create an identical XML sheet, but with the leading and trailing whitespaces of each attribute removed? (using XSLT 2.0)

Go from this:

<node id="DSN ">
    <event id=" 2190 ">
        <attribute key=" Teardown"/>
        <attribute key="Resource "/>
    </event>
</node>

To this:

<node id="DSN">
    <event id="2190">
        <attribute key="Teardown"/>
        <attribute key="Resource"/>
    </event>
</node>

I suppose I'd prefer to use the normalize-space() function, but whatever works.

  • smaccoun, Please, be aware that the currently accepted answer is wrong. It does more than what is requested, and not only removes the leading and trailing whitespace, but also reduces any enclosed whitespace to only a single space. @Gunther has provided a good XSLT 2.0 solution, that does exactly what is wanted in this question. I recommend to accept the correct answer. – Dimitre Novatchev May 16 '13 at 01:34
  • Good. The truth always wins at the end :) – Dimitre Novatchev Dec 29 '13 at 18:13
  • yup, sorry for being late to the party :) I was just putting the normalize-space() preference in there because I suspected it was necessary. In hindsight, it probably wasn't worth it, so i'm going to remove it from the question. –  Dec 30 '13 at 22:37
  • @smaccoon, Good, and Happy New Year! – Dimitre Novatchev Dec 31 '13 at 00:45

2 Answers2

21

normalize-space() will not only remove leading and trailing whitespace, but it will also install a single space character in place of any sequence of consecutive whitespace characters.

A regular expression can be used to handle just leading and trailing whitespace:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

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

  <xsl:template match="@*">
    <xsl:attribute name="{local-name()}" namespace="{namespace-uri()}">
      <xsl:value-of select="replace(., '^\s+|\s+$', '')"/>
    </xsl:attribute>
  </xsl:template>

</xsl:stylesheet>
Gunther
  • 5,146
  • 1
  • 24
  • 35
7

This should do it:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

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

  <xsl:template match="@*">
    <xsl:attribute name="{name()}">
      <xsl:value-of select="normalize-space()"/>
    </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

This is also XSLT 1.0 compatible.

When run on your sample input, the result is:

<node id="DSN">
  <event id="2190">
    <attribute key="Teardown" />
    <attribute key="Resource" />
  </event>
</node>

One thing to note here is that normalize-space() will turn any whitespace within the attribute values into single spaces, so this:

<element attr="   this    is an
                   attribute   " />

Would be changed to this:

<element attr="this is an attribute" />

If you need to keep whitespace within the value as-is, then please see Gunther's answer.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • 2
    -1 for a wrong answer. The problem is *only* to remove the leading and trailing whitespace -- and not to normalize the enclosed whitespace to a single space each. – Dimitre Novatchev May 16 '13 at 01:30
  • @DimitreNovatchev If you'd read the whole question, you would see that the asker said "I suppose I'd prefer to use the `normalize-space()` function, but whatever works." – JLRishe May 16 '13 at 05:38
  • 1
    JLRishe, This contradicts the expressed goal of the question -- most probably the OP doesn't know well what `normalize-space()` does. – Dimitre Novatchev May 16 '13 at 05:41
  • @DimitreNovatchev And it is equally plausible that the asker is fine with normalizing the rest of the space in the values and didn't overtly state it. – JLRishe May 16 '13 at 05:49
  • 1
    @JLRishe: yes that's plausible, but if they're "equally plausible", you'd be on much safer ground by informing the OP of how your solution's behavior differs from the question title; in other words, by documenting your assumption about the OP's intent. – LarsH May 16 '13 at 13:45
  • 1
    @JLRishe, If the asker was content with using `normalize-space()`, he wouldn't have asked this question. – Dimitre Novatchev May 16 '13 at 14:27
  • @DimitreNovatchev If that were true then the sentence at the end of the question would make no sense whatsoever. – JLRishe May 16 '13 at 14:38
  • 1
    @LarsH Point taken. I've added a disclaimer. – JLRishe May 16 '13 at 14:43
  • @JLRishe, LEt's wait for the OP to clarify. Anyway, Gunther's solution is precise and doesn't need any guesses / assumptions -- and he *starts* his answer by explaining the problematic behavior of `normalize-space()`. – Dimitre Novatchev May 16 '13 at 14:47
  • Removing the downvote, but not upvoting this answer as it is not as good as Gunther's and the author needed much intervention in order to introduce obvious and necessary corrections. – Dimitre Novatchev May 17 '13 at 14:47