RXC
RXC

Reputation: 1233

Replace Commas with SPace using XSLT

I am trying to remove commas from my xml file using xslt. How can I correctly replace any commas included in node or attribute values with a space?

Here is my xslt file:

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:wd="urn:com.workday/bsvc">
    <xsl:output method="text" encoding="utf-8" media-type="text/plain" />
    <xsl:strip-space  elements="*"/>

<xsl:variable name="newline" select="'&#x0A;'" />
<xsl:variable name="tab" select="'&#x09;'" />
<xsl:variable name="comma" select="'&#x2C;'" />
<xsl:variable name="padding" select="'                              '" /> <!-- 30 spaces for padding -->

<!-- Longest Column Header Text is 39 letters long -->
<xsl:variable name="FAO" select="concat('FAO', $padding, $padding)" />
<xsl:variable name="FAO1" select="concat('FAO REFERENCE ID', '')" />
<xsl:variable name="FAO2" select="concat('FAO TYPE', $padding)" />
<xsl:variable name="RESP" select="concat('RESPONSIBLE PERSON', $padding, $padding, $padding, $padding)" />


<xsl:template match="/">
<!--        <xsl:variable name="textVal" select="*/text()" />  
        <xsl:value-of select="translate($textVal, ',' ,' ')" />-->
    <xsl:value-of select="$FAO"/><xsl:value-of select="$comma"/>
    <xsl:value-of select="$FAO1"/><xsl:value-of select="$comma"/>
    <xsl:value-of select="$FAO2"/><xsl:value-of select="$comma"/>
    <xsl:value-of select="$RESP"/><xsl:value-of select="$comma"/>
<xsl:value-of select="$newline"/>

    <xsl:for-each select="/wd:Report_Data/wd:Report_Entry">
        <xsl:value-of select="substring(concat(wd:FAO, $padding, $padding, $padding, $padding, $padding), 1, string-length($FAO))" /><xsl:value-of select="$comma"/>
        <xsl:value-of select="substring(concat(wd:FAO_REFERENCE_ID, $padding, $padding, $padding, $padding, $padding), 1, string-length($FAO1))" /><xsl:value-of select="$comma"/>
        <xsl:value-of select="substring(concat(wd:FAO_TYPE, $padding, $padding, $padding, $padding, $padding), 1, string-length($FAO2))" /><xsl:value-of select="$comma"/>
        <xsl:value-of select="substring(concat(wd:RESPONSIBLE_PERSON/@wd:Descriptor, $padding, $padding, $padding, $padding, $padding), 1, string-length($RESP))" /><xsl:value-of select="$comma"/>
    </xsl:for-each>
</xsl:template>

<xsl:template match="*">
    <xsl:variable name="textVal" select="*/text()" />  
    <xsl:value-of select="translate($textVal, ',' ,' ')" />
</xsl:template>

</xsl:stylesheet>

My output is a CSV file so I want to replace any nodes and attribute values that contain commas with spaces.

The second template that tries to replace commas with a space does not work. I also tried placing those 2 statements at the start of the first template but that did not work as well.

Upvotes: 0

Views: 7911

Answers (3)

Daniel Haley
Daniel Haley

Reputation: 52888

If you're using XSLT 2.0, you could use xsl:character-map.

Example...

XML Input

<test>Bacon ipsum dolor sit amet sirloin, venison, swine, 
    ground round, pastrami, rump pig, kevin turducken.</test>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" use-character-maps="map"/>

    <xsl:character-map name="map">
        <xsl:output-character character="," string=" "/>
    </xsl:character-map>

</xsl:stylesheet>

Text Output

Bacon ipsum dolor sit amet sirloin  venison  swine  
    ground round  pastrami  rump pig  kevin turducken.

Upvotes: 1

Ian Roberts
Ian Roberts

Reputation: 122414

The translate() in your * template does nothing because that template is never used - your template match="/" just does a series of value-of instructions, it never calls apply-templates to cause the * template to fire.

You need to put the translate in each value-of individually, e.g.

<xsl:value-of select="translate(substring(concat(wd:FAO,$padding, $padding,
    $padding, $padding, $padding), 1, string-length($FAO)), ',', ' ')" />

If this were XSLT 2.0 you could define a custom function to make this a bit shorter, but in XSLT 1.0 you'd have to use apply-templates and with-param which probably works out at least as verbose as the alternative.

<xsl:for-each select="/wd:Report_Data/wd:Report_Entry">
    <xsl:apply-templates select="wd:FAO">
      <xsl:with-param name="header" select="$FAO"/>
    </xsl:apply-templates>
    <xsl:value-of select="$comma"/>
    <xsl:apply-templates select="wd:FAO_REFERENCE_ID">
      <xsl:with-param name="header" select="$FAO1"/>
    </xsl:apply-templates>
    <xsl:value-of select="$comma"/>
    <xsl:apply-templates select="wd:FAO_TYPE">
      <xsl:with-param name="header" select="$FAO2"/>
    </xsl:apply-templates>
    <xsl:value-of select="$comma"/>
    <!-- etc -->
</xsl:for-each>

with the following template

<xsl:template match="wd:*">
    <xsl:param name="header" />
    <xsl:value-of select="translate(substring(concat(., $padding, $padding,
      $padding, $padding, $padding), 1, string-length($header)), ',', ' ')" />
</xsl:template>

Upvotes: 1

therealmarv
therealmarv

Reputation: 3742

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:wd="urn:com.workday/bsvc">
    <xsl:output method="text" encoding="utf-8" media-type="text/plain" />
    <xsl:strip-space  elements="*"/>

<xsl:template match="@*|node()">
    <xsl:for-each select="@*|text()">
        <xsl:variable name="textVal" select="current()" />  
        <xsl:value-of select="translate($textVal, ',' ,' ')" />
    </xsl:for-each>
    <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions