1

我正在尝试做一些不可能的事情。

我有一个包含相同类型记录列表的 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 文档中列出的所有有效记录,并且只处理无效的特定记录。在我上面的例子中,我想要让“Suck it”失败。重视并传递所有“我是鲨鱼”。值转发到某些处理步骤以供实际使用。

不幸的是,据我所知,在 XSD 中,如果一个部分失败,则整个文档只是“糟糕”并且无法通过验证。所以,在我上面的例子中,“Suck it”。value 删除整个文档。有没有办法解决这个问题?我只是坚持我的第二个编程步骤吗?如果我只能使单个标签而不是整个文档失败,是否有某种方法可以解决“此标签因这个原因而失败”。在验证期间?

编辑:我最终使用了一个SAXParser带有Schema集合的 a ,并给它一个扩展的自定义类,该类DefaultHandler在某种程度上手动处理 XML。

Node我在我的 custom 内部设置了一个私有类DefaultHandler,这是一个非常简单的 Tree 实现。每个都Node包含一个开始标记、值和结束标记,都存储为Strings,以及与父级和子级的关系。每当我收到一条SAXException包含以“cvc-pattern-valid”或“cvc-type.3.1.3”(或我想要捕获的任何 XML 错误)开头的消息时,我都会Node从树中删除 I'm in the middle of我正在建造(因为它坏了),然后继续下一个。String然后,当我通过调用Node.depthFirstSearch()根(使用各种StringBuilders)完成解析时,我可以将整个文档(减去剔除的标签)输出为一个大 XML 。

我现在的问题是感觉就像我做了大量的工作只是为了将 XML 视为 XML。我必须重新添加 " <"、" >" 和 " <\" 字符,因为其中的方法DefaultHandler只给了我像 stripped 之类的东西qName。所有这些树的构建和遍历似乎效率低下;喜欢太多的工作。当然必须有一个更简单的方法?

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

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,覆盖DefaultHandler.error(SAXParseException exception)是正确的答案,至少对我来说。因此,Petru 得到了梦寐以求的绿色复选标记。

4

3 回答 3

1

JAXB 能够设置自定义错误处理程序,因此允许您覆盖默认行为,即放弃所有处理。用您的特定测试用例尝试一下,看看它是如何工作的。

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

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

于 2013-03-07T21:08:17.030 回答
0

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

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

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

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

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

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

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

XSD 与其他模式语言的不同之处在于,其有效性不是作为整个文档的简单布尔属性定义,而是作为已验证文档部分中每个节点的三值属性(有效、无效、未知)。像您描述的那样的使用场景(与 Stanley de Boer 在评论中提供的观点相反)是这项工作的核心动机。因此,如果您不能使用当前的 XSD 验证器做您想做的事情,那么障碍在于实现,而不是 XSD 本身。

祝你好运。

于 2013-03-07T19:10:02.943 回答
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 上。

于 2013-03-07T22:45:35.980 回答