Dané: XSLT 2.0; Saxon EE 9.6.0.4
Zdroj XML:
<clients>
<client id="1">
<address>12345 Elm Dr</address>
</client>
<client id="2">
<address>12345 Elm Cr</address>
</client>
</clients>
Potrebujem urobiť nejaké porovnanie adries, aby som našiel zhody, kde jedna adresa môže používať skratku a adresa, ktorú porovnávam, nemusí. Tu je niekoľko príkladov, čo mám na mysli:
Ave = Avenue
Blvd = Boulevard
Cir = Circle
Ct = Court
Dr = Drive
Hwy = Highway
Hľadaná adresa sa odovzdá do šablóny štýlov ako parameter, takže povedzme, že táto adresa bola odovzdaná do nasledujúcej ukážky šablóny so štýlmi:
<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>
POZNÁMKA: - Už používam preklad () na odstránenie všetkých interpunkčných znakov a veľkých písmen () na kontrolu veľkých písmen v porovnaní.
--Nemusím natrvalo vymieňať reťazce na výstupe, stačí ich vymeniť iba pre porovnanie.
--Uvedomujeme si, že toto nie je 100% spoľahlivá metóda párovania adries, ale v takom prípade to nemusíme byť ... len chceme získať ovocie s nízkou viskozitou.
Myslím si, že existuje lepší spôsob, ako to urobiť, ako 20 vnorených funkcií nahradenia alebo volanie šablóny, ktorá by prechádzala každou skratkou. Nápady?
odpovede:
2 pre odpoveď č. 1Neviem, či existuje elegantnejší spôsob ako nahradenie operáciami vnorenia / zreťazenia. Myslím si, že nejestvujú iba rôzne spôsoby vyjadrenia tejto operácie.
A čo tak pokračovať v živote:
<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)", "$1AVENUE$2")
,"(^|W)DR($|W)", "$1DRIVE$2")
,"(^|W)BLVD($|W)", "$1BOULEVARD$2")
,"(^|W)CI?R($|W)", "$1CIRCLE$2")
,"(^|W)CT($|W)", "$1COURT$2")
,"(^|W)HWY($|W)", "$1HIGHWAY$2")
" />
<xsl:template match="/">
<xsl:copy-of select="key("sanitized-adresses", upper-case($searchAddr))" />
</xsl:template>
</xsl:stylesheet>
Poznámky:
- Na
p{P}
je trieda znakov Unicode, ktorá zodpovedá všetkým interpunkčným znamienkam. - Regulárne výrazy XSLT 2.0 preto nemajú hranice slov
(^|W)
a($|W)
sú náhradami zab
. - Nemá tiež pozretia alebo pozretia, preto potrebujeme
$1
a$2
v náhradnom reťazci. - Bol som súčasťou
normalize-space()
vyhnúť sa problémom s medzerami - Na
<xsl:key>
nie je nevyhnutne potrebné, pridal som ju, aby sa hlavná šablóna príjemnejšie pozerala.
Ak chcete, vytvorte si <xsl:function>
ktorá robí sanitáciu adresy, týmto spôsobom ho môžete znova použiť na sanitáciu parametra, čo uľahčí celkové použitie.
2 pre odpoveď č. 2
Môžete zvážiť definovanie mapovania od skratiek k reťazcom, napríklad ako parameter
<xsl:param name="mapping">
<map from="Ave" to="Avenue"/>
<map from="Blvd" to="Boulevard"/>
<map from="Dr" to="Drive"/>
</xsl:param>
a potom ste mohli vybrať
<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, "$")))]"/>