Jos Nieuwenhuis


Omgaan met ampersands in SOAP berichten

Een binnenkomend SOAP bericht waarin losse ampersands (&) staan leveren problemen op bij de verwerking in BPEL of XSLT. Deze moeten eigenlijk ge-escaped worden. Bijvoorbeeld door middel van HTMLEncoding: &. Een andere mogelijkheid is om de ampersand in een CDATA sectie te plaatsen.

Het is lastig de escape uit te voeren in XSLT. Gebruik maken van de translate functie werkt niet. Onderstaand stukje code werkt wel, maar heeft een probleem.

 
<xsl:stylesheet version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:tns="urn:Services" 
      xmlns:orcl="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
      exclude-result-prefixes="xsl orcl">
  <xsl:template match="/">
    <xsl:variable name="escapedxml">
      <xsl:call-template name="replace-text">
        <xsl:with-param name="text"
            select="/tns:GetDataResponse/tns:GetDataResult"/>
        <xsl:with-param name="find" select="'&amp;'"/>
        <xsl:with-param name="replace" select="'###'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="parsedxml" select="orcl:parseEscapedXML($escapedxml)"/>
    <xsl:variable name="rooster" select="$parsedxml//Roosters"/>
    <mdw:Medewerker>
        <xsl:if test="count($rooster) > 0">
          <xsl:for-each select="$rooster">
            <mdw:rooster>
              <mdw:medewerker>       
                 <xsl:call-template name="replace-text">
                   <xsl:with-param name="text"
                        select="./medewerker"/>
                   <xsl:with-param name="find" select="'###amp;'"/>
                   <xsl:with-param name="replace" select="'&amp;'"/>
                </xsl:call-template>
              </mdw:medewerker>
            </mdw:rooster>
          </xsl:for-each>
        </xsl:if>
    </mdw:Medewerker>
  </xsl:template>
  <xsl:template name="replace-text">
    <xsl:param name="text"/>
    <xsl:param name="find"/>
    <xsl:param name="replace"/>
    <xsl:choose>
      <xsl:when test="contains($text,$find)">
        <xsl:value-of select="substring-before($text,$find)"/>
        <xsl:value-of select="$replace"/>
        <xsl:call-template name="replace-text">
          <xsl:with-param name="text" select="substring-after($text,$find)"/>
          <xsl:with-param name="find" select="$find"/>
          <xsl:with-param name="replace" select="$replace"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

Bovenstaande code is niet gunstig voor het geheugen gebruik. Door de recursieve aanroep ontstaan er veel pointers in de Java stack. Dit is vooral een probleem bij grote data sets. In sommige gevallen kan er een StackOverflow optreden. Het herschrijven van de code in Embedded Java heeft dit probleem niet:

<bpelx:exec name="Find_and_Replace_Ampersands" 
  language="java" version="1.5">
<![CDATA[
       String temp = (String) getVariableData("OutputAsString"); 
       temp = temp.replaceAll("&", "<!" + "[CDA" + "TA[&]" + "]>");         
       setVariableData("GetData_OutputVariable","parameters",
         "/ns2:GetDataResponse/ns2:GetDataResult", temp);]]>
</bpelx:exec>
Datum: 21 mei 2011 - BPEL,Java,XSLT

Geen reacties

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.