tags:

views:

54

answers:

2

I'm working with Perl and XSL. I try to change value of <Interval> to some number in an XML file. My XML looks like this:

<?xml version="1.0"?>
<Config>
    <Enabled>false</Enabled>
    <Interval>5</Interval>
</Config>

My XSL looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
        <xsl:template match="node()|@*">
    <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
    <xsl:template match="/Config/Interval">
<xsl:element name="PollingInterval">
    <xsl:element name="Interval">77</xsl:element>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

The problem is that my output has the element <Interval> twice:

<?xml version="1.0"?>
<Config>
    <Enabled>false</Enabled>
    <Interval><Interval>77</Interval></Interval>
</Config>

Please help.

A: 

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Interval/text()">77</xsl:template>
</xsl:stylesheet>

Output:

<Config>
    <Enabled>false</Enabled>
    <Interval>77</Interval>
</Config>

Note: If you post the other input sample and describe the binding, we could show you how to extract the new number.

EDIT: Shorter.

Alejandro
Thank you.Nice answer.
Toren
A: 

The problem is that my output has the element twice:

<?xml version="1.0"?> 
<Config> 
    <Enabled>false</Enabled> 
    <Interval><Interval>77</Interval></Interval>

</Config>

Not true!

The output when this transformation is applied on the provided XML document is:

<Config>
    <Enabled>false</Enabled>
    <PollingInterval><Interval>77</Interval></PollingInterval>
</Config>

In case you want to get rid of either element, simply remove the corresponding <xsl:element> instruction.

For example: Removing <xsl:element name="PollingInterval"> the transformation becomes:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/Config/Interval">
      <xsl:element name="Interval">77</xsl:element>
    </xsl:template>
</xsl:stylesheet>

and the result from applying it on the provided XML document is:

<Config>
    <Enabled>false</Enabled>
    <Interval>77</Interval>
</Config>

I recommend to simplify the transformation further and to match on the text node child of Interval. This is possibly the shortest and simplest solution:

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

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

    <xsl:template match="Interval/text()">
      <xsl:text>77</xsl:text>
    </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<Config>
    <Enabled>false</Enabled>
    <Interval>5</Interval>
</Config>

the wanted result is produced:

<Config>
    <Enabled>false</Enabled>
    <Interval>77</Interval>
</Config>

In case you have many Interval elements and want only to replace the value 5 by 77 then the only template except the identity rule should be:

<xsl:template match="Interval/text()[.=5]">
  <xsl:text>77</xsl:text>
</xsl:template>
Dimitre Novatchev
Thanks.Very helpful answer.
Toren