如何使用Schematron验证xml属性不应该包含时区信息?

时间:2012-03-13 17:28:45

标签: xml validation xsd schematron

我如何验证所有' signedWhen' xml属性不应该使用Schematron的时区信息?我正在使用使用XPath 1.0的.NET实现。

鉴于源XML:

<?xml version="1.0" encoding="utf-8"?>
<MyData versionDate="2010-12-09" dataBeginDate="2012-03-01" dataEndDate="2012-03-10" extractedWhen="2012-03-09T10:08:40">
  <Site Site_key="999">
    <SitePatient Patient_key="1">
    <txt_Surname value="TEST" signedWhen="2012-03-08T22:02:39" signedWho="SomeName"/>
    <txt_GivenNames value="PATIENT" signedWhen="2012-03-08T22:02:39" signedWho="SomeName"/>
    <dat_BirthDate value="2010-06-15" signedWhen="2012-03-08T22:02:39" signedWho="SomeName"/>
    <sel_Status value="Enrolled" signedWhen="2012-03-08T22:02:39" signedWho="SomeName"/>
    <dat_StatusDate value="2012-03-05-05:00" signedWhen="2012-03-08T22:02:39" signedWho="SomeName"/>
    </SitePatient>
  </Site>
</MyData>

在XSD文件中使用此Schematron规则:

<xs:annotation>
<xs:appinfo>
  <sch:pattern name="All signedWhen TimeZone constraints">
  <sch:rule context="*[@signedWhen]">
  <sch:assert test="(substring(@signedWhen,11,12) != '-') and (substring(@signedWhen,11,12) != '+') and (substring(@signedWhen,11,12) != 'Z')">
       <name/> must not include TimeZone information
    </sch:assert>
  </sch:rule>
  </sch:pattern> 
</xs:appinfo>  
</xs:annotation>

给出了这些不正确的结果

由于没有时区信息,因此不应返回任何结果。

NMatrix.Schematron.ValidationException: Results from Schematron validation:
Results from Schematron validation
From pattern "All signedWhen TimeZone constraints"
Assert fails: txt_Surname must not include TimeZone information
At: /MyData[1]/Site[1]/SitePatient[1]/txt_Surname[1]
    <txt_Surname value="TEST" signedWhen="2012-03-08T22:02:39" signedWho="SomeName">...</txt_Surname>
    (Line: 5, Column: 6)
Assert fails: txt_GivenNames must not include TimeZone information
At: /MyData[1]/Site[1]/SitePatient[1]/txt_GivenNames[1]
    <txt_GivenNames value="PATIENT" signedWhen="2012-03-08T22:02:39" signedWho="SomeName">...</txt_GivenNames>
    (Line: 6, Column: 6)
Assert fails: dat_BirthDate must not include TimeZone information
At: /MyData[1]/Site[1]/SitePatient[1]/dat_BirthDate[1]
    <dat_BirthDate value="2010-06-15" signedWhen="2012-03-08T22:02:39" signedWho="SomeName">...</dat_BirthDate>
    (Line: 7, Column: 6)
Assert fails: sel_Status must not include TimeZone information
At: /MyData[1]/Site[1]/SitePatient[1]/sel_Status[1]
    <sel_Status value="Enrolled" signedWhen="2012-03-08T22:02:39" signedWho="SomeName">...</sel_Status>
    (Line: 8, Column: 6)
Assert fails: dat_StatusDate must not include TimeZone information
At: /MyData[1]/Site[1]/SitePatient[1]/dat_StatusDate[1]
    <dat_StatusDate value="2012-03-05-05:00" signedWhen="2012-03-08T22:02:39" signedWho="SomeName">...</dat_StatusDate>
    (Line: 9, Column: 6)

编辑1:

我明白了。我没有使用XPath 1.0函数&#34; substring&#34;在我的测试中正确。

<sch:assert test="(substring(@signedWhen, 11, 1) != '-') and (substring(@signedWhen, 11, 1) != '+') and (substring(@signedWhen, 11, 1) != 'Z')">

编辑2: W3schools定义的xs:date和xs:dateTime没有提到可选的负面签名年份的可能性。所以我上面的代码不起作用,请参阅下面选择的答案。

编辑3: 我正在使用的模式(xmlns:xs =&#34; http://www.w3.org/2001/XMLSchema")不接受负面签名年份 - 并声明它无效。但为了安全起见,我将从现在开始使用此代码:

<sch:assert test="not ( (contains(substring(@signedWhen, 11, 2), '-')) or (contains(@signedWhen, '+')) or (contains(@signedWhen, 'Z')) )">

1 个答案:

答案 0 :(得分:1)

我不知道您是否要处理日期或日期时间,但是当我看到您的代码时,可能两者都有。您的代码在某些特定情况下不起作用。

鉴于dateTime specification

  

dateTime的词法空间由有限长度的序列组成   形式的字符:' - '? yyyy' - 'mm' - 'dd'T'hh':'mm':'ss   ('。's +)? (zzzzzz)?,其中......

您可以进一步了解详情。 (zzz)?部分是时区,如下(相同来源):

  

时区的词汇表示形式为以下形式的字符串:   (('+'|' - ')hh':'mm)| 'Z',其中......

因此,您的代码不适用于日期或日期时间,例如:-2010-03-08Z2010-03-08T12:01:02.2Z

这个应该更通用(和XPath 1.0):

test="not(
            contains(@signedWhen,'+') 
            or contains(@signedWhen,'Z') 
            or (contains(@signedWhen, 'T') 
                 and contains(substring-after(@signedWhen ,':'),'-'))
            or (not(contains(@signedWhen,'T')) and contains(@signedWhen,':'))
            )"