尝试使用Saxon针对多个架构文档验证多个XML文件时遇到了困难。这些困难是由几个元素之间存在的substitutionGroup关系引起的。这是一个简单的问题重建。
模式是:
family.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://myexample/family" xmlns:fam="http://myexample/family" xmlns="http://www.w3.org/2001/XMLSchema">
<element name="FamilyMember" type="string" />
<element name="Parent" type="string" substitutionGroup="fam:FamilyMember"/>
<element name="Child" type="string" substitutionGroup="fam:FamilyMember"/>
<element name="Family">
<complexType>
<sequence>
<element ref="fam:FamilyMember" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
</schema>
family_ext.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://myexample/family_ext" xmlns:fam="http://myexample/family" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://myexample/family" schemaLocation="http://www.valid.nl/taxo3/family.xsd"/>
<element name="Cousin" type="string" substitutionGroup="fam:FamilyMember"/>
</schema>
两个实例文件是:
family1.xml
<Family xmlns="http://myexample/family">
<Parent>John</Parent>
<Child>Alice</Child>
</Family>
family2.xml
<Family xmlns="http://myexample/family" xmlns:fam2="http://myexample/family_ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://myexample/family_ext http://www.valid.nl/taxo3/family_ext.xsd" >
<Parent>John</Parent>
<Child>Alice</Child>
<fam2:Cousin>Pete</fam2:Cousin>
</Family>
问题在于:我首先使用addSchemaSource方法将family.xsd加载到Saxon配置中。然后我验证family1.xml。这有效。如果我然后尝试验证family2.xml,我会收到以下错误:
In content of element <Family>: The content model does not allow element <Q{.../family_ext}Cousin> to appear immediately after element <{http://myexample/family}Child>. Expected <Q{.../family}FamilyMember> or nothing.
但是,如果我首先验证family2.xml,验证成功(如果我然后验证family1.xml,这也会成功)。
我发现此问题的解决方法是清除验证之间的架构缓存。然而,这最终不是一个非常令人满意的解决方案,因为在实际的用例中我有一个具有数十个模式的缓存,而不必继续重新加载它们。此外,当我开始验证时,我还不知道shemas的总集合是什么,所以我不能先抢先加载它们(在上面的例子的上下文中,我不能加载family.xsd和family_ext.xsd在验证开始时。)
为什么我执行验证的顺序很重要?有没有办法让Saxon处理这些类型的验证而不必继续清除架构缓存?
答案 0 :(得分:0)
当您加载第二个架构文档时,Saxon应该会给您一个错误,称您无法将成员添加到已用于验证的替换组中。原因是更改架构会使先前的结果无效。在XSLT / XQuery上下文中,这是相关的,因为第一个文档可能仍然存在,并且其类型注释(从模式处理派生)可能会影响它的处理方式;如果在验证时使用的模式类型与查询/转换时使用的模式类型有很大不同,那么所有类型的事情都可能出错。因此,对于您的问题的答案通常是,您应该在使用(已组装)架构之前将所有架构文档加载到Saxon配置中。事实上,规则并不那么严格,你可以安全地做出许多改变。 Saxon检查并尝试阻止的更改是添加到替代组的成员资格,并添加从现有类型扩展派生的新类型。还有其他不安全的更改,Saxon可能应该检查这些更改:例如,如果添加一个名为X的新全局元素声明,那么如果它被松散地验证,则可以使包含名为X的元素的内容无效。
我不知道为什么撒克逊在添加到替换组时没有报告错误。我会调查一下。
这里实际发生的是,用于Family元素的匿名复杂类型被编译为用于验证过程的有限状态机。此FSM考虑了已知的替换组成员。看起来原始的FSM用于验证新元素,而不考虑已添加新的替换组成员。
后来:我试图按如下方式重现:
Processor proc = new Processor(true);
SchemaManager sm = proc.getSchemaManager();
sm.load(new StreamSource(new StringReader(sch1)));
System.err.println("Schema 1 OK");
sm.newSchemaValidator().validate(new StreamSource(new StringReader(doc1)));
System.err.println("Doc 1 OK");
sm.load(new StreamSource(new StringReader(sch2)));
System.err.println("Schema 2 OK");
sm.newSchemaValidator().validate(new StreamSource(new StringReader(doc2)));
System.err.println("Doc 2 OK");
其中sch1,sch2,doc1和doc2是您的示例文档和模式。在加载sch2时,我得到了我的期望:
net.sf.saxon.s9api.SaxonApiException: It is not possible to add to the
substitution group of element FamilyMember in namespace 'http://myexample/family',
because the schema for that namespace has already been used for validating instance
documents, or for compiling queries or stylesheets