Search code examples
xmlxslt

XSLT Select of decode values


Below is my XML Sample. Looks like the values are encoded.
I am creating sample xslt template like so

<xsl:value-of select="fee_number"/>

how do I decode values so that they are presented normally? Thanks.

<fees>
  <fee>
    <fee_number>_x0031_645111</fee_number>
    <fee_type>Property_x0020_Registration_x0020_Fee</fee_type>
    <fee_issued_date>_x0030_1_x002F_01_x002F_2023</fee_issued_date>
    <fee_amount>_x0024_13.00</fee_amount>
    <fee_transfer_date>_x0030_5_x002F_12_x002F_2023</fee_transfer_date>
    <fee_transfer_status>Yes</fee_transfer_status>
  </fee>
  <fee>
    <fee_number>_x0031_459853</fee_number>
    <fee_type>Property_x0020_Registration_x0020_Fee</fee_type>
    <fee_issued_date>_x0030_1_x002F_01_x002F_2022</fee_issued_date>
    <fee_amount>_x0024_13.00</fee_amount>
    <fee_transfer_date>_x0030_5_x002F_16_x002F_2022</fee_transfer_date>
    <fee_transfer_status>Yes</fee_transfer_status>
  </fee>
</fees>

Solution

  • In case anyone needs to do this in pure XSLT 1.0, with no extensions, here is a relatively simple way - provided some assumptions are true, namely:

    1. Every code starts with "_x00" (i.e. all encoded characters are from the Extended ASCII charset);

    2. There are no occurrences of "_x00" in the text except at the start of a code;

    3. The output method is XML or HTML;

    4. The XSLT processor supports disable-output-escaping;

    5. The XSLT processor does the serializing (IOW, the output goes directly to a file).

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="text()">
        <xsl:call-template name="decode">
            <xsl:with-param name="text" select="."/>
        </xsl:call-template>
    </xsl:template>
    
    <xsl:template name="decode">
        <xsl:param name="text"/>
        <xsl:choose>
            <xsl:when test="contains($text, '_x00')">
                <!-- text before -->
                <xsl:value-of select="substring-before($text, '_x00')"/>
                <!-- decode -->
                <xsl:variable name="hex" select="substring-before(substring-after($text, '_x00'), '_')" />
                <xsl:value-of select="concat('&amp;#x', $hex, ';')" disable-output-escaping="yes"/>
                <!-- recursive call with text after -->
                <xsl:call-template name="decode">
                    <xsl:with-param name="text" select="substring-after(substring-after($text, '_x00'), '_')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$text"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    </xsl:stylesheet>
    

    Using the given input, the result here will be:

    <?xml version="1.0" encoding="UTF-8"?>
    <fees>
      <fee>
        <fee_number>&#x31;645111</fee_number>
        <fee_type>Property&#x20;Registration&#x20;Fee</fee_type>
        <fee_issued_date>&#x30;1&#x2F;01&#x2F;2023</fee_issued_date>
        <fee_amount>&#x24;13.00</fee_amount>
        <fee_transfer_date>&#x30;5&#x2F;12&#x2F;2023</fee_transfer_date>
        <fee_transfer_status>Yes</fee_transfer_status>
      </fee>
      <fee>
        <fee_number>&#x31;459853</fee_number>
        <fee_type>Property&#x20;Registration&#x20;Fee</fee_type>
        <fee_issued_date>&#x30;1&#x2F;01&#x2F;2022</fee_issued_date>
        <fee_amount>&#x24;13.00</fee_amount>
        <fee_transfer_date>&#x30;5&#x2F;16&#x2F;2022</fee_transfer_date>
        <fee_transfer_status>Yes</fee_transfer_status>
      </fee>
    </fees>
    

    which any conforming XML parser will read exactly the same as:

    <?xml version="1.0" encoding="UTF-8"?>
    <fees>
      <fee>
        <fee_number>1645111</fee_number>
        <fee_type>Property Registration Fee</fee_type>
        <fee_issued_date>01/01/2023</fee_issued_date>
        <fee_amount>$13.00</fee_amount>
        <fee_transfer_date>05/12/2023</fee_transfer_date>
        <fee_transfer_status>Yes</fee_transfer_status>
      </fee>
      <fee>
        <fee_number>1459853</fee_number>
        <fee_type>Property Registration Fee</fee_type>
        <fee_issued_date>01/01/2022</fee_issued_date>
        <fee_amount>$13.00</fee_amount>
        <fee_transfer_date>05/16/2022</fee_transfer_date>
        <fee_transfer_status>Yes</fee_transfer_status>
      </fee>
    </fees>