使用 xslt 标记化和 for-each 的字符串操作 [英] string manipulation using xslt tokenize and for-each
问题描述
我正在尝试更新下面 xml 中的信用卡号,标记化不起作用,你能看看我在这里遗漏了什么吗?
i am trying to update the creditcard number in the below xml, tokenize is not working, can you please look what i missing here?
输入 XML:
<Payment>
<CreditCardDetails>
<CreditCard>
<Amount>31.0</Amount>
<CreditCardType>American Express</CreditCardType>
<CreditHolderName>test</CreditHolderName>
<Number>41111111111111</Number>
<ExpiryMonth>8</ExpiryMonth>
<ExpiryYear>2015</ExpiryYear>
</CreditCard>
<CreditCard>
<Amount>31.0</Amount>
<CreditCardType>AMERICAN EXPRESS</CreditCardType>
<CreditHolderName></CreditHolderName>
<Number>34123456544333</Number>
<ExpiryMonth>8</ExpiryMonth>
<ExpiryYear>2015</ExpiryYear>
</CreditCard>
<CreditCard>
<Amount>31.0</Amount>
<CreditCardType>Visa</CreditCardType>
<CreditHolderName>exman</CreditHolderName>
<Number>43434343434434343</Number>
<ExpiryMonth>8</ExpiryMonth>
<ExpiryYear>2015</ExpiryYear>
</CreditCard>
</CreditCardDetails>
</Payment>
我正在尝试的 XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:str="http://exslt.org/strings"
exclude-result-prefixes="#all" >
<xsl:output method="xml" cdata-section-elements="Payment" omit-xml-declaration="yes" />
<!-- copy all elements and their attributes-->
<xsl:template match="* | @*">
<xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match="//*[local-name()='Payment']">
<xsl:variable name="inXML" select="text()"/>
<xsl:variable name="updatedCards">
<xsl:variable name="openCardDetailsTag"><xsl:value-of select="'<CreditCardDetails>'"/></xsl:variable>
<xsl:variable name="closeCardDetailsTag"><xsl:value-of select="'</CreditCardDetails>'"/></xsl:variable>
<xsl:variable name="openCNTag"><xsl:value-of select="'<Number>'"/></xsl:variable>
<xsl:variable name="closeCNTag"><xsl:value-of select="'</Number>'"/></xsl:variable>
<xsl:variable name="openCCTag"><xsl:value-of select="'<CreditCardType>'"/></xsl:variable>
<xsl:variable name="closeCCTag"><xsl:value-of select="'</CreditCardType>'"/></xsl:variable>
<xsl:variable name="allcreditCards" select="normalize-space(substring-before(substring-after($inXML,$openCardDetailsTag),$closeCardDetailsTag))"/>
<xsl:for-each select="str:tokenize($allcreditCards,'<CreditCard>')">
<xsl:variable name="Number" select="normalize-space(substring-before(substring-after(.,$openCNTag),$closeCNTag))"/>
<xsl:variable name="IncomingccType" select="normalize-space(substring-before(substring-after(.,$openCCTag),$closeCCTag))"/>
<xsl:variable name="BeforeCreditcard" select="normalize-space(substring-before(.,$openCNTag))"/>
<xsl:variable name="AfterCreditcard" select="normalize-space(substring-after(.,$closeCNTag))"/>
<xsl:variable name="newCard">
<xsl:call-template name="updateCard">
<xsl:with-param name="ccNum" select="$Number"/>
<xsl:with-param name="ccType" select="$IncomingccType"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="updatedCards">
<xsl:value-of select="concat($updatedCards,$beforeCardNumber,$openCardNumberTag,$newCard,$closeCardNumberTag,$afterCardNumber)"/>
</xsl:variable>
</xsl:for-each>
<xsl:element name="Payment" >
<xsl:value-of select="$updatedCards"/>
</xsl:element>
</xsl:template>
<xsl:template name="updateCard">
<xsl:param name="ccNum"/>
<xsl:param name="ccType"/>
<xsl:variable name="firstDigit" select="substring($ccNum,1,1)"/>
<xsl:variable name="firstTwoDigits" select="substring($ccNum,1,2)"/>
<xsl:variable name="ccTypeFromNumber">
<xsl:choose>
<xsl:when test="firstTwoDigits ='34' or $firstTwoDigits ='37'">
<xsl:value-of select="'AMERICAN EXPRESS'"/>
</xsl:when>
<xsl:when test="$firstDigit ='4'">
<xsl:value-of select="'Visa'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="UNKNOWN"></xsl:value-of>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$ccType = $ccTypeFromNumber">
<xsl:value-of select="concat($ccNum,$ccType)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="WrongNumber"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
期待输出 XML:
<Payment>
<CreditCardDetails>
<CreditCard>
<Amount>31.0</Amount>
<CreditCardType>American Express</CreditCardType>
<CreditHolderName>test</CreditHolderName>
<Number>WrongNumber</Number>
<ExpiryMonth>8</ExpiryMonth>
<ExpiryYear>2015</ExpiryYear>
</CreditCard>
<CreditCard>
<Amount>31.0</Amount>
<CreditCardType>AMERICAN EXPRESS</CreditCardType>
<CreditHolderName></CreditHolderName>
<Number>34123456544333AMERICAN EXPRESS</Number>
<ExpiryMonth>8</ExpiryMonth>
<ExpiryYear>2015</ExpiryYear>
</CreditCard>
<CreditCard>
<Amount>31.0</Amount>
<CreditCardType>Visa</CreditCardType>
<CreditHolderName>exman</CreditHolderName>
<Number>41111111111111111Visa</Number>
<ExpiryMonth>8</ExpiryMonth>
<ExpiryYear>2015</ExpiryYear>
</CreditCard>
</CreditCardDetails>
</Payment>
尝试用 NewNumber 替换信用卡号,我可以知道如何实现吗?
trying to replace creditcard number with NewNumber, may i know how i can achieve this?
推荐答案
str:tokenize($allcreditCards,'<CreditCard>')
这不能按预期工作,因为第二个参数中的每个字符都被视为分隔字符 - 请参阅:http://www.exslt.org/str/functions/tokenize/index.html
This cannot work as expected, because each character in the second argument is taken as a delimiting character - see: http://www.exslt.org/str/functions/tokenize/index.html
您可以使用递归处理模板自己标记化"输入.
You could "tokenize" the input yourself, using a recursive processing template.
修改后的样式表:
<?xml version="1.0" encoding="UTF-8"?>
<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:template match="/">
<Payment>
<xsl:call-template name="replaceNumbers">
<xsl:with-param name="string" select="Payment" />
</xsl:call-template>
</Payment>
</xsl:template>
<xsl:template name="replaceNumbers">
<xsl:param name="string"/>
<xsl:param name="openNum" select="'<Number>'"/>
<xsl:param name="closeNum" select="'</Number>'"/>
<xsl:param name="openType" select="'<CreditCardType>'"/>
<xsl:param name="closeType" select="'</CreditCardType>'"/>
<xsl:choose>
<xsl:when test="contains($string, $openNum) and contains(substring-after($string, $openNum), $closeNum)" >
<xsl:value-of select="substring-before($string, $openNum)" />
<xsl:value-of select="$openNum" />
<xsl:call-template name="updateCard">
<xsl:with-param name="ccType" select="substring-before(substring-after($string, $openType), $closeType)" />
<xsl:with-param name="ccNum" select="substring-before(substring-after($string, $openNum), $closeNum)" />
</xsl:call-template>
<xsl:value-of select="$closeNum" />
<!-- recurse -->
<xsl:call-template name="replaceNumbers">
<xsl:with-param name="string" select="substring-after($string, $closeNum)" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="updateCard">
<xsl:param name="ccType"/>
<xsl:param name="ccNum"/>
<!-- INSERT YOUR PROCESS HERE -->
<xsl:value-of select="concat($ccNum, $ccType)" />
</xsl:template>
</xsl:stylesheet>
注意:如果 CC 可以在没有前面数字的情况下输入,您可能希望包含更多测试.
Note: you might want to include more tests, if it's possible for a CC to come in without a type before the number.
这篇关于使用 xslt 标记化和 for-each 的字符串操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!