Luiz
Luiz

Reputation: 151

How to escape greater than and less than sign on all the child elements of a particular element in XML using XSL?

I am new to XML and XSL. I have got a requirement write an XSL script to replace the greater than (>) and less than (<) sign of some child elements with the escape strings. I need to perform the replace on the child elements within the "startupXml" element (see code below)

<?xml version="1.0" encoding="utf-8" ?>
<s:Envelope  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <Startup2 xmlns="http://keyfax.touch-base.com/">
            <startupXml>
                <KeyfaxData>
                    <Startup>
                        <Config>Test</Config>
                        <Mode>RD</Mode>
                        <UserName>JBLOG</UserName>
                        <PropertyType>P</PropertyType>
                        <PropertyID>L0000</PropertyID>
                        <ReferenceID>12345</ReferenceID>
                        <Property>
                            <ContactHistory/>
                        </Property>
                    </Startup>
                </KeyfaxData>
            </startupXml>
        </Startup2>
    </s:Body>
</s:Envelope>

The result should look like this:

<?xml version="1.0" encoding="utf-8" ?>
<s:Envelope  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <Startup2 xmlns="http://keyfax.touch-base.com/">
            <startupXml>
                &lt;KeyfaxData&gt;
                    &lt;Startup&gt;
                        &lt;Config&gt;Test&lt;/Config&gt;
                        &lt;Mode&gt;RD&lt;/Mode&gt;
                        &lt;UserName&gt;JBLOG&lt;/UserName&gt;
                        &lt;PropertyType&gt;P&lt;/PropertyType&gt;
                        &lt;PropertyID&gt;L0000&lt;/PropertyID&gt;
                        &lt;ReferenceID&gt;12345&lt;/ReferenceID&gt;
                        &lt;Property&gt;
                            &lt;ContactHistory/&gt;
                        &lt;/Property&gt;
                    &gt;/Startup&lt;
                &gt;/KeyfaxData&lt;
            </startupXml>
        </Startup2>
    </s:Body>
</s:Envelope>

I've tried some xsl scripts to find and replace, but as I am new to XML and XSL, the outcome was not successful. Could someone point me in the correct direction please.

Thanks in advance.

Upvotes: 1

Views: 5263

Answers (2)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22617

In this general case (escaping all descendant elements of a particular input element), you could use

XSLT Stylesheet (online)

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:kf="http://keyfax.touch-base.com/">
    <xsl:output method="xml" omit-xml-declaration="no" encoding="UTF-8" indent="yes" />

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

    <xsl:template match="kf:startupXml//*">
        <xsl:value-of select="concat('&lt;',name(),'&gt;')"/>
            <xsl:apply-templates/>
        <xsl:value-of select="concat('&lt;/',name(),'&gt;')"/>
    </xsl:template>

</xsl:transform>

XML Output

Your expected output immediately closes the ContactHistory element: &lt;Contact History/&gt;, but that would require additional logic.

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <Startup2 xmlns="http://keyfax.touch-base.com/">
            <startupXml>
                &lt;KeyfaxData&gt;
                    &lt;Startup&gt;
                        &lt;Config&gt;Test&lt;/Config&gt;
                        &lt;Mode&gt;RD&lt;/Mode&gt;
                        &lt;UserName&gt;JBLOG&lt;/UserName&gt;
                        &lt;PropertyType&gt;P&lt;/PropertyType&gt;
                        &lt;PropertyID&gt;L0000&lt;/PropertyID&gt;
                        &lt;ReferenceID&gt;12345&lt;/ReferenceID&gt;
                        &lt;Property&gt;
                            &lt;ContactHistory&gt;&lt;/ContactHistory&gt;
                        &lt;/Property&gt;
                    &lt;/Startup&gt;
                &lt;/KeyfaxData&gt;
            </startupXml>
        </Startup2>
    </s:Body>
</s:Envelope>

Upvotes: 3

Michael Kay
Michael Kay

Reputation: 163352

The main thing you need to bear in mind is that XSLT doesn't see the markup, it sees the tree of nodes formed by parsing the markup. So you need a template rule something like this:

<xsl:template match="*" mode="escape-markup">
  <xsl:text>&lt;</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:text>&gt;</xsl:text>
  <xsl:apply-templates mode="#current"/>
  <xsl:text>&lt;/</xsl:text>
  <xsl:value-of select="name()"/>
  <xsl:text>&gt;</xsl:text>
</xsl:template>

which you then invoke when you hit the relevant element:

<xsl:template match="startUpXml">
  <xsl:apply-templates mode="escape-markup"/>
</xsl:template>

It gets a little more complicated if you have to handle attributes and namespaces.

Upvotes: 1

Related Questions