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