在xQuery中查找具有特定属性值的XML数据库中的元素

时间:2016-09-22 14:56:15

标签: xml xquery

我面临以下问题陈述:

对于由两个或多个其他行政单位共同管理的每个行政单位,请核实:

  • 它通过使用managedBy关联角色来引用这些共同管理单位。
  • 这些共同管理单位中的每一个都使用coAdminister协会角色来指代上述共同管理单位。

数据库如下所示:

house_id

我编写了以下xQuery表达式:

FactoryGirl.define do
  factory :user do
    house
    house_id { House.find_by(user_id: id).id }
  end
end 

然而,我总是得到'失败',即使这不应该。

我认为问题出在声明中:

<?xml version "1.0" ?>
<wfs:FeatureCollection xmlns:au="http://inspire.ec.europa.eu/schemas/au/4.0"
xmlns:gts="http://www.isotc211.org/2005/gts" xmlns:gco="http://www.isotc211.org/2005/gco"
xmlns:ns1="http://www.w3.org/1999/xhtml"
xmlns:hfp="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty"
xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:gn="http://inspire.ec.europa.eu/schemas/gn/4.0"
xmlns:gss="http://www.isotc211.org/2005/gss" xmlns:gsr="http://www.isotc211.org/2005/gsr"
xmlns:base="http://inspire.ec.europa.eu/schemas/base/3.3"
xmlns:gmd="http://www.isotc211.org/2005/gmd" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wfs="http://www.opengis.net/wfs/2.0"
xsi:schemaLocation="http://inspire.ec.europa.eu/schemas/au/4.0 http://inspire.ec.europa.eu/schemas/au/4.0/AdministrativeUnits.xsd http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd"
numberMatched="274" numberReturned="274" timeStamp="2016-03-29T18:12:51.630+02:00">
<wfs:member>
    <au:AdministrativeUnit gml:id="NC.MT01402">
        <au:administeredBy xlink:href="#NC.MT01310"/>
        <au:administeredBy xlink:href="#NC.MT01407"/>
        <au:coAdminister nilReason="Unpopulated"/>
    </au:AdministrativeUnit>
</wfs:member>
<wfs:member>
    <au:AdministrativeUnit gml:id="NC.MT01310">
        <au:administeredBy nilReason="Unpopulated" xsi:nil="true"/>
        <au:coAdminister xlink:href="#NC.MT01402"/>
    </au:AdministrativeUnit>
</wfs:member>
<wfs:member>
    <au:AdministrativeUnit gml:id="NC.MT01407">
        <au:upperLevelUnit xlink:href="#NC.MT0xxxx"/>
        <au:administeredBy nilReason="Unpopulated" xsi:nil="true"/>
        <au:coAdminister xlink:href="#NC.MT01402"/>
     </au:AdministrativeUnit>
</wfs:member>
</wfs:FeatureCollection>

因为$ coAdminVal似乎总是空的。

我已经尝试了其他几种方式来编写这个陈述,但结果都是错误的:

let $administrativeUnits := $features[self::*:AdministrativeUnit]

let $featuresWithErrors :=
    (for $candidate in $administrativeUnits
        let $administeredBy := $candidate/au:administeredBy/@xlink:href
        let $candidateVal := string($candidate/@gml:id)
     return
       if (count($administeredBy) >= 2) then (
          let $coAdminCheck :=
            (for $administer in $administeredBy
                let $administerVal := string($administer)
                let $coAdminVal := $administrativeUnits/au:AdministrativeUnit[@gml:id = $administerVal]/au:coAdminister/@xlink:href
                return
                    if (string($coAdminVal) = $candidateVal) then () else $administer
            )

            return
                 if ($coAdminCheck) then $candidate else ()
       )        
       else ()


)[position() le $limitErrors]
return
(if ($featuresWithErrors) then 'FAILED' else 'PASSED', 
 local:error-statistics('TR.featuresWithErrors', count($featuresWithErrors)),
 for $feature in $featuresWithErrors
   order by $feature/@gml:id
   return local:addMessage('TR.noCoAdministered', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': string($feature/@gml:id), 'adminBy' : string($feature/au:administeredBy[1]/@xlink:href) })) 

这样做的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

我同意,看起来问题在于谓词中的比较表达式:

[@gml:id = $administerVal]

由于$administerVal基本上是au:administeredBy/@xlink:href属性,让我们来看看你要比较的内容:

gml:id="NC.MT01402"
xlink:href="#NC.MT01310"
xlink:href="#NC.MT01407"

区别在于@xlink:href值前面带有#符号。要解决此问题,请将您的比较更改为:

[@gml:id = substring-after($administerVal, "#")]

您使用contains()的其他方法失败,因为您询问NC.MT01402之类的值是否包含#NC.MT01402。反转参数将起作用。

同样适用于matches() - 尽管请注意此函数采用正则表达式模式,因此.之类的字符将匹配任何字符,而不仅仅是文字句点字符。要强制搜索文字句点字符,您需要将其转义,例如matches("#NC.MT01402", "NC\.MT01402")

考虑到matches()的额外复杂性(除非你真的想要模式匹配而不是文字比较),我会说$administerVal使用substring()或使用contains()进行修剪是std::bitset最好的方法。