Hi Folks,
I am looking for a solution as to how I can mask some data that is part of a CDATA element.

My currently implemented xslt-1 script works fine when my xml element/attribute is not placed inside cdata, for example, in the following xml snippet, I masked <CreditCardNumber> element's data:

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<fareRequest da="true">
<vcrs>
  <vcr>U2</vcr>
</vcrs>
<fareTypes/>
<tourOps/>
<flights>
  <flight depApt="SXF" depDate="2012-04-19" dstApt="BUD"/>
  <flight depApt="BUD" depDate="2012-04-25" dstApt="SXF"/>
</flights>
<CreditCardNumber>123456123</CreditCardNumber>
<limit>20</limit>
<offset>0</offset>
<waitOnList>
  <waitOn>ALL</waitOn>
</waitOnList>
<coses/>
</fareRequest>

XSLT-1 Script:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.2" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ota="http://www.opentravel.org/OTA/2003/05" xmlns:anyway="http://anyway.com/webservices/" xmlns:k="http://webservices.kuoni.ch" xmlns:xft="http://www.exchangefortravel.org/xft/current" xmlns:tu="http://tempuri.org/" xmlns:jet2="http://Jet2.Com/External/2009/01/V4">
<xsl:output encoding="UTF-8" version="1.0" method="xml" indent="yes" cdata-section-elements="anyway:request k:request k:ForwardRequestResult xft:NameText xft:Description xft:URL xft:From xft:To xft:Code tu:XRq tu:ProcessTransactionXFTUResult libelle nom prenom adresse1 ville pays email"/>
<xsl:strip-space elements="*"/>
<!--add coma separated element names without namespace prefix to be masked, dont remove first coma! -->
<xsl:param name="names">!,Number,CCV,cc_number,cc_cvv,AccountNumber,CardSecurityCode,card_number,options,CreditCardNumber,CardNumber,IssueNumber,SecurityCode,</xsl:param>
<xsl:template match="/">
  <xsl:apply-templates select="node()"/>
</xsl:template>
<xsl:template match="@*">
  <xsl:variable name="attr-name" select="concat(',' , local-name() , ',')"/>
  <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
   <xsl:choose>
    <xsl:when test="string-length(substring-before($names, $attr-name)) > 0">
     <xsl:call-template name="mask"/>
    </xsl:when>
    <xsl:otherwise>
     <xsl:value-of select="."/>
    </xsl:otherwise>
   </xsl:choose>
  </xsl:attribute>
</xsl:template>
<xsl:template match="text()">
  <xsl:copy/>
</xsl:template>
<xsl:template match="*">
  <xsl:variable name="el-name" select="concat(',' , local-name(), ',')"/>
  <xsl:choose>
   <xsl:when test="string-length(substring-before($names, $el-name)) > 0">
    <xsl:element name="{name()}" namespace="{namespace-uri()}">
     <xsl:call-template name="mask"/>
    </xsl:element>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates select="*"/>
   </xsl:when>
   <xsl:otherwise>
    <xsl:element name="{name()}" namespace="{namespace-uri()}">
     <xsl:apply-templates select="@*"/>
     <xsl:apply-templates/>
    </xsl:element>
   </xsl:otherwise>
  </xsl:choose>
</xsl:template>
<xsl:template name="index-of">
  <xsl:param name="param1"/>
  <xsl:param name="param2"/>
  <xsl:value-of select="string-length(substring-before(concat(' ' ,$param1), $param2))"/>
</xsl:template>
<xsl:template name="mask">
  <xsl:variable name="length" select="string-length(.)"/>
  <xsl:choose>
   <xsl:when test="$length > 3">
    <xsl:value-of select="concat ('************', substring(.,$length - 1, 2))"/>
   </xsl:when>
   <xsl:when test="$length > 1">***</xsl:when>
   <xsl:otherwise/>
  </xsl:choose>
</xsl:template>
</xsl:stylesheet>

Output XML:

<?xml version="1.0" encoding="UTF-8"?>
<fareRequest da="true">
<vcrs>
  <vcr>U2</vcr>
</vcrs>
<fareTypes/>
<tourOps/>
<flights>
  <flight depApt="SXF" depDate="2012-04-19" dstApt="BUD"/>
  <flight depApt="BUD" depDate="2012-04-25" dstApt="SXF"/>
</flights>
<CreditCardNumber>************23</CreditCardNumber>
<limit>20</limit>
<offset>0</offset>
<waitOnList>
  <waitOn>ALL</waitOn>
</waitOnList>
<coses/>
</fareRequest>

In the above example <CreditCardNumber>************23</CreditCardNumber> is masked properly.

But when in my XML, I have the following scenario:

<?xml version="1.0" encoding="UTF-8"?>
<fareRequest da="true">
<vcrs>
  <vcr>U2</vcr>
</vcrs>
<fareTypes/>
<tourOps/>
<flights>
  <flight depApt="SXF" depDate="2012-04-19" dstApt="BUD"/>
  <flight depApt="BUD" depDate="2012-04-25" dstApt="SXF"/>
</flights>
<![CDATA[<CreditCardNumber>123456123</CreditCardNumber>]]>
<limit>20</limit>
<offset>0</offset>
<waitOnList>
  <waitOn>ALL</waitOn>
</waitOnList>
<coses/>
</fareRequest>

That is <CreditCardNumber> inside CDATA, the script does not mask the data. Or in other words, everything that is contained inside CDATA, is ignored because it is not considered as an element or attribute by the xslt processor.

Could somebody help me out in fixing this problem?

Please note that my script is in XSLT 1.

Thanks.

Could you put the CDATA credit card number value into a variable and then use that instead of trying to read the node?

CC number is just an example, there could be any other element or set of elements. The main requirement is to take what ever is inside the CData and then mask it.
The idea is to take the CData content, apply masking on it and then put it back in the CData.

text inside a CDATA section will be ignored by the parser.

w3schools quote.

You will have to have the data another way or manipulate it externally to XSLT as in the CDATA section if simply wont even be looked at

i got it solved with xslt.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:strip-space elements="" /> 
<xsl:output method="xml" indent="yes" encoding="utf-8" 
cdata-section-elements="fareRequest" /> 
<xsl:template match="|@|text()|processing-instruction()|comment()"> 
<xsl:copy> 
<xsl:apply-templates select="|@*|text()|processing-instruction()|comment()" /> 
</xsl:copy> 
</xsl:template>

<xsl:template match="text()"> 
<xsl:choose> 
<xsl:when test="starts-with(normalize-space(.), '&lt;CreditCardNumber&gt;')"> 
<xsl:value-of select="translate(.,'0123456789','****')" /> 
</xsl:when> 
<xsl:otherwise> 
<xsl:value-of select="." /> 
</xsl:otherwise> 
</xsl:choose> 
</xsl:template>

</xsl:stylesheet>
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.