This will be the conclusion to our series on the
DTYPE_PHONE phone challenge.
This solution will pick up where the last article left of from and I am assuming that you already have a WF and have queried your IO to get your message.
For added fun, this is our new beefed up XML message.
<phone>
<home>+610296480999
(00) 0000 0000</home>
<work>+610296480888
(00) 0000 0000</work>
<mobile>+610401123456
0000 000 000</mobile>
<voip>+610296480222
00 0000 0000</voip>
<mum>+610296480111
(00) 00 00 00 00</mum>
<dad>+610296480333
0000 0000</dad>
<brother>+610296480444
00 0000 0000</brother>
<sister>+610296480555
000000000</sister>
</phone>
We will use the technique in the first article to split the phone and pattern using XSLT, and also
apply the phone formatting in the same transaction!
Heres the new XSLT that will do the magic for us.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:variable name="CRLF"><xsl:text> </xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/home"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/work"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/mobile"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/voip"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/mum"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/dad"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/brother"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/sister"/></xsl:call-template>
</xsl:template>
<xsl:template name="applyPhoneFormat">
<xsl:param name="dtypephone"/>
<xsl:param name="output"/>
<xsl:param name="num" select="substring-before($dtypephone, $CRLF)" />
<xsl:param name="pattern" select="substring-after($dtypephone, $CRLF)" />
<xsl:param name="ploop" select="string-length($pattern)" />
<xsl:param name="nloop" select="string-length($num)" />
<xsl:variable name="patterncursor" select="substring($pattern, $ploop , 1 )" />
<xsl:variable name="numbercursor" select="substring($num, $nloop , 1 )" />
<xsl:choose>
<xsl:when test="$ploop > 0">
<xsl:choose>
<xsl:when test="$patterncursor = 0">
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop - 1"/>
<xsl:with-param name="output" select="concat($numbercursor,$output)" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop"/>
<xsl:with-param name="output" select="concat($patterncursor,$output)" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($output,$CRLF)" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
To make this solution work, we needed to have cursors that loops through the phone pattern and build the phone string, but since there is no concept of looping in XSLT (we have the for-each, but that just iterates over the XML nodes, it dosnt do a custom for loop for us), i have used the next best thing, which is build a recursive template to give us the same effect.
I originally designed this solution 3 years ago, but sadly never kept a copy of it when i moved on. So the XSLT you see here is a re-write of the original.
Whenever we use a new technology in our environment, and especially when it uses loops, its prudent to do performance testing to ensure it runs as expected. When i did my testing on the original XSLT against the Xalan (Siebel's XSLT translator which uses the Xerces 1.1 parser) engine in version 7.5, i used a dummy XML with 100 phone numbers, and each phone number had between 8-10 characters for the phone number. When i analysed the logs, the transaction completed within a split millisecond.
This is only a proof of concept, and dosnt handle cases where the user enters the correct phone format, and the system needs to lookup the correct number format, and in the above solution i've chopped of the country code.
The XSLT above hasnt been performance tested, so before you use it in your environment take sometime to analyse the XSLT logic to ensure it meets your needs, and test its performance in your environment, you should be quite surprised by the Xalan engines efficiency.
In the example above, i've included the special formatting characters, but Alex from
Siebel Essentials has requested that i show how to send only the numeric phone number.
This was achieved in the
first article in the series, by using XSLT to split the phone and pattern portions.
To apply the correct format with spacing, but not non numeric characters such as (,),/,- etc. In other words, we are stripping off all the special characters and just applying the correct spacing.
To do this we just need to modify our XSLT a little.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:variable name="CRLF"><xsl:text> </xsl:text></xsl:variable>
<xsl:variable name="SP"><xsl:text> </xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/home"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/work"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/mobile"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/voip"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/mum"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/dad"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/brother"/></xsl:call-template>
<xsl:call-template name="applyPhoneFormat"><xsl:with-param name="dtypephone" select="phone/sister"/></xsl:call-template>
</xsl:template>
<xsl:template name="applyPhoneFormat">
<xsl:param name="dtypephone"/>
<xsl:param name="output"/>
<xsl:param name="num" select="substring-before($dtypephone, $CRLF)" />
<xsl:param name="pattern" select="substring-after($dtypephone, $CRLF)" />
<xsl:param name="ploop" select="string-length($pattern)" />
<xsl:param name="nloop" select="string-length($num)" />
<xsl:variable name="patterncursor" select="substring($pattern, $ploop , 1 )" />
<xsl:variable name="numbercursor" select="substring($num, $nloop , 1 )" />
<xsl:choose>
<xsl:when test="$ploop > 0">
<xsl:choose>
<xsl:when test="$patterncursor = 0">
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop - 1"/>
<xsl:with-param name="output" select="concat($numbercursor,$output)" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$patterncursor = $SP">
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop"/>
<xsl:with-param name="output" select="concat($patterncursor,$output)" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="applyPhoneFormat">
<xsl:with-param name="dtypephone" select="$dtypephone"/>
<xsl:with-param name="ploop" select="$ploop - 1"/>
<xsl:with-param name="nloop" select="$nloop"/>
<xsl:with-param name="output" select="$output" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($output,$CRLF)" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Before we leave this topic, i want to touch on the
original challenge, which was to retrieve the phone number portion from the DTYPE_PHONE field without using any scripting, and although we've achieved that, plus a whole lot more. Some could argue that the XSLT solution is a form of scripting, but without all the negative associations.
Its not quite black or white, so i'll leave that for you to think about.
Stay tuned for more Impossible solutions!