XQuery/字串分析
XSLT 2.0 包含 analyze-string 結構,它捕獲正則表示式中匹配的組(在括號中)。奇怪的是,這在 XQuery 中不可用。可以透過將 XQuery 函式包裝在生成的 XSLT 樣式表周圍來使用 XSLT 結構,即使這似乎相當痛苦。在這個 eXist 安裝中,XSLT 引擎是 Saxon 8。
declare function str:analyze-string($string as xs:string, $regex as xs:string,$n as xs:integer ) {
transform:transform
(<any/>,
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match='/' >
<xsl:analyze-string regex="{$regex}" select="'{$string}'" >
<xsl:matching-substring>
<xsl:for-each select="1 to {$n}">
<match>
<xsl:value-of select="regex-group(.)"/>
</match>
</xsl:for-each>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>,
()
)
};
為了說明此功能的使用,這裡有一個英國車輛牌照的解碼器。這些格式經過多次更改,因此指令碼必須首先確定使用哪種格式,然後分析號碼以找到區域和註冊日期的重要程式碼。模式在 XML 中定義,並定義要使用的正則表示式以及匹配組的含義。
問題:傳遞重複修飾符失敗
import module namespace str = "http://www.cems.uwe.ac.uk/string" at "../lib/string.xqm";
declare variable $patterns :=
<patterns>
<pattern version="01" regexp="([A-Z][A-Z])(\d\d)[A-Z][A-Z][A-Z]">
<field>Area</field><field>Date</field>
</pattern>
<pattern version="83" regexp="([A-Z])\d+[A-Z]([A-Z][A-Z])">
<field>Date</field><field>Area</field>
</pattern>
<pattern version="63" regexp="([A-Z][A-Z])[A-Z]?\d+([A-Z])">
<field>Area</field><field>Date</field>
</pattern>
</patterns>;
declare function local:decode-regno($regno) {
let $regno := upper-case($regno)
let $regno := replace($regno, " ","")
return
for $pattern in $patterns/pattern
let $regexp := concat("^",$pattern/@regexp,"$")
return
if (matches($regno,$regexp))
then
let $analysis := str:analyze-string($regno,$regexp,count($pattern/field))
return
<regno version="{$pattern/@version}">
{for $field at $i in $pattern/field
let $value := string($analysis[position() = $i])
let $table := concat($field,$pattern/@version)
let $value := /CodeList[@id=$table]/Entry[Code=$value]
return
element {$field} {$value/*}
}
</regno>
else
()
};
let $regno := request:get-parameter("regno",())
return local:decode-regno($regno)
單獨的表將程式碼解碼為日期範圍或區域。這些表是透過 Excel 從 CSV 檔案建立的純 XML。83 年前的區域程式碼目前不正確。
例如:
<CodeList id="Area83"> <Entry> <Code>AA</Code> <Location>Bournemouth</Location> </Entry> <Entry> <Code>AB</Code> <Location>Worcester</Location> </Entry> <Entry> <Code>AC</Code> <Location>Coventry</Location> </Entry> ...
此轉換的一種用途是在地圖上顯示位置。在這裡,我們獲取觀察到的註冊號碼檔案,對其進行解碼,按位置分組,並生成一個 KML 檔案,其中位置透過 Google API 進行地理編碼。
<NumberList>
<Regno>H251GBU</Regno>
<Regno>WRA870Y</Regno>
<Regno>ENB427T</Regno>
<Regno>C406OUY</Regno>
<Regno>N62VNF</Regno>
<Regno>R895KCV</Regno>
<Regno>C758HOV</Regno>
<Regno>H541HEM</Regno>
...
(: this script plots the registration locations of a set of UK vehicle license plates using kml. :)
import module namespace geo="http://www.cems.uwe.ac.uk/exist/geo" at "../lib/geo.xqm";
import module namespace str = "http://www.cems.uwe.ac.uk/string" at "../lib/string.xqm";
declare namespace reg = "http://www.cems.uwe.ac.uk/wiki/reg";
declare option exist:serialize "method=xml media-type=application/vnd.google-earth.kml+xml indent=yes omit-xml-declaration=yes";
declare variable $reg:icon := "http://maps.google.com/mapfiles/kml/paddle/ltblu-blank.png";
declare variable $reg:patterns :=
<patterns>
<pattern version="01" regexp="([A-Z][A-Z])(\d\d)[A-Z][A-Z][A-Z]">
<field>Area</field><field>Date</field>
</pattern>
<pattern version="83" regexp="([A-Z])\d+[A-Z]([A-Z][A-Z])">
<field>Date</field><field>Area</field>
</pattern>
<pattern version="63" regexp="([A-Z][A-Z])[A-Z]?\d+([A-Z])">
<field>Area</field><field>Date</field>
</pattern>
</patterns>;
declare function reg:decode-regno($regno) {
let $regno := upper-case($regno)
let $regno := replace($regno, " ","")
return
for $pattern in $reg:patterns/pattern
let $regexp := concat("^",$pattern/@regexp,"$")
return
if (matches($regno,$regexp))
then
let $analysis := str:analyze-string($regno,$regexp,count($pattern/field))
return
<regno version="{$pattern/@version}">
{for $field at $i in $pattern/field
let $value := string($analysis[position() = $i])
let $table := concat($field,$pattern/@version)
let $value := /CodeList[@id=$table]/Entry[Code=$value]
return
element {$field} {$value/*}
}
</regno>
else
()
};
declare function reg:regno-locations($regnos) {
for $regno in $regnos
let $analysis := reg:decode-regno($regno)
return
if (exists($analysis//Location))
then string($analysis//Location)
else ()
};
let $url := request:get-parameter("url",())
let $x := response:set-header('Content-Disposition','inline;filename=regnos.kml;')
return
<Document>
<name>Reg nos</name>
{for $i in (1 to 10)
return
<Style id="size{$i}">
<IconStyle>
<scale>{$i}</scale>
<Icon><href>{$reg:icon}</href> </Icon>
</IconStyle>
</Style>
}
{
let $locations := reg:regno-locations(doc($url)//Regno)
let $max := count($locations)
for $place in distinct-values($locations)
let $latlong := geo:geocode(concat($place,',UK'))
let $count := count($locations[. = $place])
let $scale := max((round($count div $max * 10),1))
order by $count descending
return
<Placemark>
<name>{$place} ({$count})</name>
<styleUrl>#size{$scale}</styleUrl>
<Point><coordinates>{geo:position-as-kml($latlong)}</coordinates></Point>
</Placemark>
}
</Document>
資訊科學與數字媒體系支援一個簡訊服務,它具有傳送和接收簡訊的功能。該服務由英格蘭西部大學布里斯托爾分校支付,所有流量均已記錄。
英國車輛牌照號碼的解碼器是支援移動發起 (MO) 文字訊息的演示服務之一。
簡訊格式為
REG L052
例如 447624803759
以這種格式傳送到我們的簡訊手機號碼447624803759的簡訊會透過一個 PHP 指令碼,該指令碼允許支援多個簡訊服務。該指令碼使用訊息的第一個單詞來識別相關服務端點,然後透過 HTTP 呼叫該端點,將字首作為code、訊息的其餘部分作為text以及原手機號碼作為from傳遞。
對於字首 REG,相關端點是 XQuery 指令碼
http://www.cems.uwe.ac.uk/xmlwiki/regno/smsregno.xq
smsregno.xq 指令碼本質上是上面的 parseregno 指令碼。
declare option exist:serialize "method=text media-type=text/text";
...
let $regno := request:get-parameter("text",())
let $data := local:decode-regno($regno)
return
concat("Reply: ",
$regno ,
" was registered in ",
$data/Area/Location,
" between ",
$data/Date/From ,
" and ",
$data/Date/To
)
然後簡訊交換機將回復發送到原手機。
- 解決重複修飾符問題(或對 analayze-string 的函式支援)
- 83 年前的區域程式碼資料
- 在 XQuery 中切換實現以替換 PHP 應用程式 - 等待切換到 eXist v2