【问题标题】:How to validate that xml attributes should not have time zone information using Schematron?如何使用 Schematron 验证 xml 属性不应包含时区信息?
【发布时间】:2012-03-30 03:31:48
【问题描述】:

如何使用 Schematron 验证所有 'signedWhen' xml 属性不应包含时区信息?我正在使用使用 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 函数“子字符串”。

<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="http://www.w3.org/2001/XMLSchema")不接受负符号年份 - 并声明它无效。但为了安全起见,我将从现在开始使用此代码:

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

【问题讨论】:

    标签: xml validation xsd schematron


    【解决方案1】:

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

    鉴于dateTime specification

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

    您可以进一步阅读以了解详细信息。 (zzz)? 部分是时区,如下(同一来源):

    时区的词法表示是以下形式的字符串: (('+' | '-') hh ':' mm) | 'Z',在哪里...

    因此,您的代码不适用于 date 或 dateTime,例如:-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,':'))
                )"
    

    【讨论】:

    • 我的代码应该适用于你的一个例子“2010-03-08T..”,但你是对的,它不适用于“-2010-03-08Z”我没有意识到那是可能,但此时我只检查 xs:Date,但将它扩展到 xs:dateTime 是有意义的,就像你将来需要的那样。谢谢!
    • 我的代码基于 xs:date 为“w3schools.com/schema/schema_dtypes_date.asp”,它表示“+”和“-”必须在日期之后并且与“T”相同,所以如果这是真的,我的代码对于 xs:date - AFAIK 将是 100% 正确的。还可以在 xs:dateTime 页面往下看,我的代码也将 100% 兼容...?
    • 对于dateTime,时区位于末尾,因此它不在字符串表示中的第 11 位。关于第一个“-”,它只涉及 BC 日期而不涉及时区。我认为您提到的 w3school 页面忘记了关于第一个“-”(公元前日期)的这一点。如有任何疑问,我更喜欢查看 w3c rec(上面的 dateTime 链接)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多