如何使用 XSLT 2.0 替换地址字符串中的多个地址缩写
How to replace multiple address abbreviations in an address string using XSLT 2.0
给定:XSLT 2.0;撒克逊 EE 9.6.0.4
来源XML:
<clients>
<client id="1">
<address>12345 Elm Dr</address>
</client>
<client id="2">
<address>12345 Elm Cr</address>
</client>
</clients>
我需要对地址进行一些比较,以找到一个地址可能使用缩写而我正在比较的地址可能没有的匹配项。以下是我的意思的几个例子:
Ave = Avenue
Blvd = Boulevard
Cir = Circle
Ct = Court
Dr = Drive
Hwy = Highway
搜索到的地址作为参数传递给样式表,假设该地址传递给以下示例样式表:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="searchAddr">12345 Elm Drive</xsl:param>
<xsl:variable name="punctuation">
<xsl:text> .!@#$%^*()_+{}[]|`\:;?,*-=/</xsl:text>
</xsl:variable>
<xsl:template match="/">
<xsl:for-each select="clients/client[address[upper-case(translate(.,$punctuation,'')) = upper-case(translate($searchAddr,$punctuation,''))]]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
注意:
--我已经在使用 translate() 删除所有标点符号和 upper-case() 来控制比较中的大小写。
--我不需要永久替换输出中的字符串,我只需要替换它们以进行比较。
--我们意识到这不是 100% 可靠的地址匹配方法,但在这种情况下,我们不需要它...只是想轻松实现。
我认为有比 20 个嵌套替换函数或调用模板循环遍历每个缩写更好的方法。想法?
不知道有没有比nesting/chaining20次替换操作更优雅的方法。我认为没有,只是表达该操作的方式不同。
那么继续生活怎么样:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:param name="searchAddr">12345 Elm Drive</xsl:param>
<xsl:key name="sanitized-adresses" match="client" use="
replace(
replace(
replace(
replace(
replace(
replace(
replace(
upper-case(normalize-space(address))
,'\p{P}', '')
,'(^|\W)AVE($|\W)', 'AVENUE')
,'(^|\W)DR($|\W)', 'DRIVE')
,'(^|\W)BLVD($|\W)', 'BOULEVARD')
,'(^|\W)CI?R($|\W)', 'CIRCLE')
,'(^|\W)CT($|\W)', 'COURT')
,'(^|\W)HWY($|\W)', 'HIGHWAY')
" />
<xsl:template match="/">
<xsl:copy-of select="key('sanitized-adresses', upper-case($searchAddr))" />
</xsl:template>
</xsl:stylesheet>
备注:
\p{P}
是匹配所有标点符号的Unicode字符class。
- XSLT 2.0 正则表达式没有单词边界,因此
(^|\W)
和 ($|\W)
是 \b
. 的替代品
- 它也没有后视或前视,因此我们需要在替换字符串中使用
</code> 和 <code>
。
- 我包含了
normalize-space()
以避免空白问题
<xsl:key>
不是绝对必要的,我添加它是为了使主模板看起来更美观。
如果你愿意,可以创建一个<xsl:function>
来进行地址清理,这样你就可以重复使用它来清理参数,使整体使用更加方便。
您可以考虑定义从缩写到字符串的映射,例如作为参数
<xsl:param name="mapping">
<map from="Ave" to="Avenue"/>
<map from="Blvd" to="Boulevard"/>
<map from="Dr" to="Drive"/>
</xsl:param>
然后你可以select
<xsl:copy-of select="clients/client[matches(address, concat('^', $searchAddr, '$')) or (some $map in $mapping/map satisfies matches(replace(address, $map/@from, $map/@to), concat('^', $searchAddr, '$')))]"/>
给定:XSLT 2.0;撒克逊 EE 9.6.0.4
来源XML:
<clients>
<client id="1">
<address>12345 Elm Dr</address>
</client>
<client id="2">
<address>12345 Elm Cr</address>
</client>
</clients>
我需要对地址进行一些比较,以找到一个地址可能使用缩写而我正在比较的地址可能没有的匹配项。以下是我的意思的几个例子:
Ave = Avenue
Blvd = Boulevard
Cir = Circle
Ct = Court
Dr = Drive
Hwy = Highway
搜索到的地址作为参数传递给样式表,假设该地址传递给以下示例样式表:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="searchAddr">12345 Elm Drive</xsl:param>
<xsl:variable name="punctuation">
<xsl:text> .!@#$%^*()_+{}[]|`\:;?,*-=/</xsl:text>
</xsl:variable>
<xsl:template match="/">
<xsl:for-each select="clients/client[address[upper-case(translate(.,$punctuation,'')) = upper-case(translate($searchAddr,$punctuation,''))]]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
注意: --我已经在使用 translate() 删除所有标点符号和 upper-case() 来控制比较中的大小写。
--我不需要永久替换输出中的字符串,我只需要替换它们以进行比较。
--我们意识到这不是 100% 可靠的地址匹配方法,但在这种情况下,我们不需要它...只是想轻松实现。
我认为有比 20 个嵌套替换函数或调用模板循环遍历每个缩写更好的方法。想法?
不知道有没有比nesting/chaining20次替换操作更优雅的方法。我认为没有,只是表达该操作的方式不同。
那么继续生活怎么样:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:param name="searchAddr">12345 Elm Drive</xsl:param>
<xsl:key name="sanitized-adresses" match="client" use="
replace(
replace(
replace(
replace(
replace(
replace(
replace(
upper-case(normalize-space(address))
,'\p{P}', '')
,'(^|\W)AVE($|\W)', 'AVENUE')
,'(^|\W)DR($|\W)', 'DRIVE')
,'(^|\W)BLVD($|\W)', 'BOULEVARD')
,'(^|\W)CI?R($|\W)', 'CIRCLE')
,'(^|\W)CT($|\W)', 'COURT')
,'(^|\W)HWY($|\W)', 'HIGHWAY')
" />
<xsl:template match="/">
<xsl:copy-of select="key('sanitized-adresses', upper-case($searchAddr))" />
</xsl:template>
</xsl:stylesheet>
备注:
\p{P}
是匹配所有标点符号的Unicode字符class。- XSLT 2.0 正则表达式没有单词边界,因此
(^|\W)
和($|\W)
是\b
. 的替代品
- 它也没有后视或前视,因此我们需要在替换字符串中使用
</code> 和 <code>
。 - 我包含了
normalize-space()
以避免空白问题 <xsl:key>
不是绝对必要的,我添加它是为了使主模板看起来更美观。
如果你愿意,可以创建一个<xsl:function>
来进行地址清理,这样你就可以重复使用它来清理参数,使整体使用更加方便。
您可以考虑定义从缩写到字符串的映射,例如作为参数
<xsl:param name="mapping">
<map from="Ave" to="Avenue"/>
<map from="Blvd" to="Boulevard"/>
<map from="Dr" to="Drive"/>
</xsl:param>
然后你可以select
<xsl:copy-of select="clients/client[matches(address, concat('^', $searchAddr, '$')) or (some $map in $mapping/map satisfies matches(replace(address, $map/@from, $map/@to), concat('^', $searchAddr, '$')))]"/>