XSD - 失败一些,通过一些

时间:2013-03-07 18:11:01

标签: xml validation xsd jaxb

我正在尝试做一些可能无法做到的事情。

我有一个XML文档,其中包含相同类型的记录列表。像这样:

<root>
  <record>I'm a shark.</record>
  <record>I'm a shark.</record>
  <record>Suck it.</record>
  <record>I'm a shark.</record>
</root>

首先,我通过XSD运行它以确保标记是正确的。然后,我解组它并对实际值进行一些编程验证。我想通过<xs:pattern />将第二步折叠到XSD中(匹配正则表达式的值以测试有效性)。

问题是我有业务规则,我应该继续处理XML文档中列出的所有有效的记录,并且只有那些没有的特定记录才会失败。在上面的例子中,我想失败的“吮吸它”。价值并传递所有“我是鲨鱼”。值继续到实际使用的某个处理步骤。

不幸的是,据我所知,在XSD中,如果一个部分失败,整个文档只是“坏”并且验证失败。所以,在上面的例子中,“吮吸它”。值会删除整个文档。这有什么办法吗?我只是坚持我的第二个程序步骤?如果我 只能使单个标签失败而不是整个文档,那么是否有某种方法可以获得“此标签因此而失败”。验证期间?

修改:我最终使用了SAXParser并设置了Schema,并将其交给了DefaultHandler的自定义类,该类有点手动处理XML。

我在自定义Node内部设置了一个私有类DefaultHandler,这是一个非常简单的Tree实现。每个Node都包含一个开头标记,值和结束标记,全部存储为String s,以及与父级和子级的关系。每当我得到一个SAXException包含以“cvc-pattern-valid”或“cvc-type.3.1.3”开头的消息(或者我想要捕获的任何XML错误)时,我删除了Node我正处于我正在建造的树中间(因为它已经坏了),然后继续前进到下一个。然后,当我通过调用根(使用各种String s)上的Node.depthFirstSearch()进行解析时,我可以将整个文档(减去剔除的标签)输出为大的XML StringBuilder。 / p>

我现在的问题是,感觉我只是将XML作为XML来处理过多的工作。我必须重新添加“<”,“>”和“<\”字符,因为DefaultHandler中的方法只能为我提供剥离的内容{ {1}}。所有这些树木建造和遍历似乎效率低下;喜欢太多的工作。当然必须有一个更简单的方法吗?

注意:我想将XML保留为XML的原因是因为这是我以前的工作流程:

qName

现在就是这样:

XSD -> XSLT -> Unmarshal to JAXB-Annotated Object

也许有一些神奇的方法可以做:

SAXParser(XSD) -> XSLT -> Unmarshal to JAXB-Annotated Object

或者

SAXParser(XSD, XSLT) -> Unmarshal to JAXB-Annotated Object

但我不知道会是什么。

编辑嗯,除了可能的低效率,延长SAXParser(XSD, XSLT, Unmarshal to JAXB-Annotated Object) ,覆盖DefaultHandler是正确的答案,至少对我而言。所以Petru获得了令人垂涎的绿色复选标记。

3 个答案:

答案 0 :(得分:1)

JAXB能够设置custom error handler,从而允许您覆盖默认行为,即放弃所有处理。尝试使用您的特定测试用例,并了解它的工作原理。

据我所知,所有主要的验证器都有一个基于事件的方法,允许自定义处理验证错误,以便继续处理。

最糟糕的情况可能是使用例如SAX API实际解析XML - 而不是直接使用JAXB - 它可以让您更好地控制处理错误;然后,无论成功验证了哪个record节点,都将解组到您的JAVA类中(尽管最终会进行双重解析)。

答案 1 :(得分:0)

让我们区分概念层面和实际层面。

从概念上讲 - XSD不仅定义了整个文档的有效性(或者更具体地说,定义了验证开始的文档节点),还定义了以验证开始的节点为根的子树中的每个节点。

因此,在您的文档的PSVI(模式后验证信息集)中,每个“记录”元素在概念上都标有[validity = valid]或[validity = invalid]或[validity = notKnown]。正如您所观察到的,无效性向上传播,因此如果父“root”元素具有无效子元素,它通常也将无效。

XSD规范没有说明发现其输入无效的应用程序是继续处理输入还是中止;这超出了XSD规范的范围。如果您想处理有效的“记录”元素并使用无效的元素执行其他操作,则XSD规范旨在使验证程序能够为您提供所需的信息。

实际上 - 许多用户和一些实现者没有看到XSD定义的更丰富的有效性概念的效用,因此许多验证器和代码绑定工具提供的API默认情况下基本上将有效性降低到验证的单个布尔属性root,在某些方面,这种有效的概念是工具实际支持的唯一一个。

因此,验证者的API可能会也可能不会让您访问“记录”元素的有效性信息。如果是这样,您只需编写消费代码来询问API并采取相应措施。如果没有,您需要告诉您的供应商您需要该信息(或寻找不同的验证器)。如果您使用数据绑定工具生成代码,则适用相同的原则:了解如何使您的工具生成可在无效输入存在的情况下进行攻击的代码,如果该工具不支持,请询问供应商为什么不呢。

XSD不会尝试为验证器定义API或最低质量标准,因此说服供应商提供对XSD完全本地有效性概念的访问的唯一方法是通过市场压力。

XSD与其他模式语言的不同之处在于,部分定义有效性不是作为整体文档的简单布尔属性,而是作为文档部分中每个节点的三值属性(有效,无效,未知)已经过验证。您所描述的使用场景(与Stanley de Boer在评论中提供的观点相反)是该作品的核心动机。因此,如果您无法使用当前的XSD验证器执行所需操作,则障碍在于实现,而不在于XSD本身。

祝你好运。

答案 2 :(得分:0)

Saxon没有Michael Sperberg-McQueen所描述的理想化XSD处理器,主要是因为它主要是为了满足模式感知XSLT和XQuery处理的需求而设计,它们不需要XSD规范中内置的所有灵活性。但是,您仍然可以获得很长的路要走,因为您并不需要完整的PSVI:您需要的是源文档以及错误列表[我的术语,而不是XSD规范中使用的术语],链接在一起某种方式。而且你可以轻松地做到这一点 - 细节取决于你是否想要基于树或基于事件的处理方法。

(其他XSD处理器几乎也是如此,但Saxon是我最熟悉的那个)。

如果您正确选择处理选项,Saxon将始终在验证错误后继续运行,但在某些情况下,它将决定不对文档的某些部分进行任何进一步验证。例如,如果内容模型应该包含(a,b,c,d)并且实例实际包含(a,x,b,c,d),那么一旦在x处报告错误,则不进行验证在b,c和d上。