XSLT 1.0 搜索替换给定字符串中的缩写
XSLT 1.0 Search Replace Abbreviation In Given String
我正在处理一项要求,地址文本中的北、南、东、西应替换为 N、S、E、W
我已经在试用以下模板
<xsl:template name="string-replace-all">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)"/>
<xsl:value-of select="$by"/>
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
上述模板的问题是我必须在同一文本上一遍又一遍地重复此模板 4 次。我正在寻找一些全面的解决方案。有的话请告诉我。
来源XML
<sam:process>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road North</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road SOUTH EAST</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road North EAST</sam:ADDR1>
</sam:DETAIL>
预期XML输出
<sam:process>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road N</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road SE</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road NE</sam:ADDR1>
</sam:DETAIL>
最接近的版本XSLT 1.0:
来源
<sam:process xmlns:sam="baum">
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road North</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road SOUTH EAST</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road North EAST</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Northwood Road North EAST</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Southfield Road South WEst</sam:ADDR1>
</sam:DETAIL>
</sam:process>
结果
<sam:process xmlns:sam="baum">
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road N</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road S E</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road N E</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Northwood Road N E</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Southfield Road S W</sam:ADDR1>
</sam:DETAIL>
</sam:process>
样式表
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:sam="baum">
<xsl:variable name="upperChars" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="lowerChars" select="'abcdefghijklmnopqrstuvwxyz'"/>
<!-- identity copy template -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- change this matching node -->
<xsl:template match="sam:ADDR1">
<xsl:copy>
<xsl:call-template name="replaceRules">
<!-- wrap the string with spaces!
important, otherwise some searchterms wont be found if they are at the beginning or end -->
<xsl:with-param name="string" select="concat(' ', ., ' ')"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<!-- template to 'rule them all' -->
<xsl:template name="replaceRules">
<xsl:param name="string"/><!-- original string -->
<!-- change from upper to lower case, to search just once for each searchterm - more or less case insensitiv -->
<xsl:variable name="lowerString" select="translate($string, $upperChars, $lowerChars)" />
<!-- rules -->
<xsl:choose>
<xsl:when test="contains($lowerString, ' north ')">
<xsl:call-template name="replaceRules">
<xsl:with-param name="string">
<xsl:call-template name="replaceRule">
<xsl:with-param name="string" select="$string"/>
<xsl:with-param name="searchstring" select="$lowerString"/>
<xsl:with-param name="searchterm" select="' north '"/>
<xsl:with-param name="replacement" select="' N '" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($lowerString, ' east ')">
<xsl:call-template name="replaceRules">
<xsl:with-param name="string">
<xsl:call-template name="replaceRule">
<xsl:with-param name="string" select="$string"/>
<xsl:with-param name="searchstring" select="$lowerString"/>
<xsl:with-param name="searchterm" select="' east '"/>
<xsl:with-param name="replacement" select="' E '" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($lowerString, ' south ')">
<xsl:call-template name="replaceRules">
<xsl:with-param name="string">
<xsl:call-template name="replaceRule">
<xsl:with-param name="string" select="$string"/>
<xsl:with-param name="searchstring" select="$lowerString"/>
<xsl:with-param name="searchterm" select="' south '"/>
<xsl:with-param name="replacement" select="' S '" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($lowerString, ' west ')">
<xsl:call-template name="replaceRules">
<xsl:with-param name="string">
<xsl:call-template name="replaceRule">
<xsl:with-param name="string" select="$string"/>
<xsl:with-param name="searchstring" select="$lowerString"/>
<xsl:with-param name="searchterm" select="' west '"/>
<xsl:with-param name="replacement" select="' W '" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- remove leading and trailing spaces -->
<xsl:value-of select="normalize-space($string)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- applying one single rule to string - not more unusual replacement function needed, cause i search in a lower case string BUT get substring from the original string-->
<xsl:template name="replaceRule">
<xsl:param name="string" /> <!-- original text -->
<xsl:param name="searchstring" /><!-- lower case text -->
<xsl:param name="searchterm" /><!-- search for xyz -->
<xsl:param name="replacement" /><!-- replace xyz with -->
<xsl:variable name="lengthAfter" select="string-length(substring-after($searchstring, $searchterm))"/>
<xsl:value-of select="
concat(
substring(
$string,
1,
string-length(substring-before($searchstring, $searchterm))
),
$replacement,
substring(
$string,
string-length($searchstring) - $lengthAfter + 1,
$lengthAfter
)
)"/>
</xsl:template>
</xsl:stylesheet>
我正在处理一项要求,地址文本中的北、南、东、西应替换为 N、S、E、W
我已经在试用以下模板
<xsl:template name="string-replace-all">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)"/>
<xsl:value-of select="$by"/>
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
上述模板的问题是我必须在同一文本上一遍又一遍地重复此模板 4 次。我正在寻找一些全面的解决方案。有的话请告诉我。
来源XML
<sam:process>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road North</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road SOUTH EAST</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road North EAST</sam:ADDR1>
</sam:DETAIL>
预期XML输出
<sam:process>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road N</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road SE</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road NE</sam:ADDR1>
</sam:DETAIL>
最接近的版本XSLT 1.0:
来源
<sam:process xmlns:sam="baum">
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road North</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road SOUTH EAST</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road North EAST</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Northwood Road North EAST</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Southfield Road South WEst</sam:ADDR1>
</sam:DETAIL>
</sam:process>
结果
<sam:process xmlns:sam="baum">
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road N</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road S E</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Old Country Road N E</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Northwood Road N E</sam:ADDR1>
</sam:DETAIL>
<sam:DETAIL>
<sam:CITY>Hicksville</sam:CITY>
<sam:ZIP>11801</sam:ZIP>
<sam:ADDR1>Southfield Road S W</sam:ADDR1>
</sam:DETAIL>
</sam:process>
样式表
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:sam="baum">
<xsl:variable name="upperChars" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="lowerChars" select="'abcdefghijklmnopqrstuvwxyz'"/>
<!-- identity copy template -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- change this matching node -->
<xsl:template match="sam:ADDR1">
<xsl:copy>
<xsl:call-template name="replaceRules">
<!-- wrap the string with spaces!
important, otherwise some searchterms wont be found if they are at the beginning or end -->
<xsl:with-param name="string" select="concat(' ', ., ' ')"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<!-- template to 'rule them all' -->
<xsl:template name="replaceRules">
<xsl:param name="string"/><!-- original string -->
<!-- change from upper to lower case, to search just once for each searchterm - more or less case insensitiv -->
<xsl:variable name="lowerString" select="translate($string, $upperChars, $lowerChars)" />
<!-- rules -->
<xsl:choose>
<xsl:when test="contains($lowerString, ' north ')">
<xsl:call-template name="replaceRules">
<xsl:with-param name="string">
<xsl:call-template name="replaceRule">
<xsl:with-param name="string" select="$string"/>
<xsl:with-param name="searchstring" select="$lowerString"/>
<xsl:with-param name="searchterm" select="' north '"/>
<xsl:with-param name="replacement" select="' N '" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($lowerString, ' east ')">
<xsl:call-template name="replaceRules">
<xsl:with-param name="string">
<xsl:call-template name="replaceRule">
<xsl:with-param name="string" select="$string"/>
<xsl:with-param name="searchstring" select="$lowerString"/>
<xsl:with-param name="searchterm" select="' east '"/>
<xsl:with-param name="replacement" select="' E '" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($lowerString, ' south ')">
<xsl:call-template name="replaceRules">
<xsl:with-param name="string">
<xsl:call-template name="replaceRule">
<xsl:with-param name="string" select="$string"/>
<xsl:with-param name="searchstring" select="$lowerString"/>
<xsl:with-param name="searchterm" select="' south '"/>
<xsl:with-param name="replacement" select="' S '" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($lowerString, ' west ')">
<xsl:call-template name="replaceRules">
<xsl:with-param name="string">
<xsl:call-template name="replaceRule">
<xsl:with-param name="string" select="$string"/>
<xsl:with-param name="searchstring" select="$lowerString"/>
<xsl:with-param name="searchterm" select="' west '"/>
<xsl:with-param name="replacement" select="' W '" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- remove leading and trailing spaces -->
<xsl:value-of select="normalize-space($string)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- applying one single rule to string - not more unusual replacement function needed, cause i search in a lower case string BUT get substring from the original string-->
<xsl:template name="replaceRule">
<xsl:param name="string" /> <!-- original text -->
<xsl:param name="searchstring" /><!-- lower case text -->
<xsl:param name="searchterm" /><!-- search for xyz -->
<xsl:param name="replacement" /><!-- replace xyz with -->
<xsl:variable name="lengthAfter" select="string-length(substring-after($searchstring, $searchterm))"/>
<xsl:value-of select="
concat(
substring(
$string,
1,
string-length(substring-before($searchstring, $searchterm))
),
$replacement,
substring(
$string,
string-length($searchstring) - $lengthAfter + 1,
$lengthAfter
)
)"/>
</xsl:template>
</xsl:stylesheet>