XmlBeans - 针对类型而非元素的XSD验证

时间:2014-02-10 15:53:42

标签: java xml xsd xsd-validation xmlbeans

我需要使用XmlBeans对以下XSD中声明的(复杂)类型验证以下XML。

我的XSD:

<xs:schema targetNamespace="http://www.xxx.com/xmlns/osb/WS2CICS/program/PROG1/p1" attributeFormDefault="unqualified" elementFormDefault="qualified"
  xmlns="http://www.xxx.com/xmlns/osb/WS2CICS/program/PROG1/p1"
  xmlns:ct="http://www.xxx.com/xmlns/osb/WS2CICS/common"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <!--xs:element name="Param" type="ParamType"/-->

    <xs:complexType name="ParamType">
        <xs:sequence>
            <xs:element name="Text" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

我的XML:

<Param xsi:type="p1:ParamType"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.xxx.com/xmlns/osb/WS2CICS/Envelope/v01"
  xmlns:p1="http://www.xxx.com/xmlns/osb/WS2CICS/program/PROG1/p1">

    <p1:Text>abc</p1:Text>

</Param>

我基本上使用this site中的代码来使用XmlBeans进行XML验证。但验证失败,并且元素“Param”的消息为"Invalid type"。只有在XSD中取消注释“Param”元素声明并在通过向其添加命名空间前缀p1:来更改XML中的“Param”命名空间之后,验证才会成功 - 即在对元素声明进行验证时,不是类型声明。

我需要的是:

  1. 使用XmlBeans
  2. 以某种方式告诉XmlBeans XML根目录中的元素"{http://www.xxx.com/xmlns/osb/WS2CICS/Envelope/v01}Param"是否正常(无需检查)。
  3. 告诉XmlBeans根是复杂类型"{http://www.xxx.com/xmlns/osb/WS2CICS/program/PROG1/p1}ParamType"(检查孩子)
  4. 我该怎么做?

    背景:

    我有一个消息信封,其中“Param”元素的类型为“anyType”,即它可以包含任何内容。在特定情况下,我需要检查“Param”是否具有由动态选择的XSD给出的特定内容。我可以很容易地检查信封的有效性,但在第二步中,我还需要检查Param的有效性。

    编辑:重新措辞

2 个答案:

答案 0 :(得分:1)

您需要记住,XSD架构文件只能有一个目标命名空间。你在这里要做的是在命名空间http://www.example.com/xmlns/osb/WS2CICS/program/PROG1/p1中定义complexType'ParamType',在命名空间http://www.example.com/xmlns/osb/WS2CICS/Envelope/v01中定义'param'元素。您应该使用两个xsd模式(导入另一个)并更改您的XMLValidator类以获取其他xsd文件输入,如下所示 -

input.xsd -

<xs:schema targetNamespace="http://www.example.com/xmlns/osb/WS2CICS/Envelope/v01"                         attributeFormDefault="unqualified" elementFormDefault="qualified"
 xmlns:p1="http://www.example.com/xmlns/osb/WS2CICS/program/PROG1/p1"
 xmlns="http://www.example.com/xmlns/osb/WS2CICS/program/PROG1/p1"
 xmlns:ct="http://www.example.com/xmlns/osb/WS2CICS/common"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:import namespace="http://www.example.com/xmlns/osb/WS2CICS/program/PROG1/p1                      root.xsd"/>

 <xs:element name="Param" type="ParamType"/> 

</xs:schema>

root.xsd -

 <xs:schema targetNamespace="http://www.example.com/xmlns/osb/WS2CICS/program/PROG1/p1" attributeFormDefault="unqualified" elementFormDefault="qualified"
 xmlns="http://www.example.com/xmlns/osb/WS2CICS/program/PROG1/p1"
 xmlns:ct="http://www.example.com/xmlns/osb/WS2CICS/common"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:complexType name="ParamType">
    <xs:sequence>
        <xs:element name="Text" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

XMLValidator -

 ...
 public boolean validate(File dataFile, File schemaFile, File schemaFile2) {
 ...

 ...
 XmlObject[] schemas = { XmlObject.Factory.parse(schemaFile,
                new XmlOptions().setLoadLineNumbers()
                        .setLoadMessageDigest()), XmlObject.Factory.parse(schemaFile2,
                                new XmlOptions().setLoadLineNumbers()
                                .setLoadMessageDigest()) };
 ...

在input.xsd中导入root.xsd时,需要正确指向root.xsd。如果发现问题,可以使用root.xsd的绝对路径。

答案 1 :(得分:0)

我找不到使用XmlBeans如何针对XSD类型验证元素的直接方法。但是我通过为缺少的元素声明动态创建模式找到了一种解决方法:

/**
 * Validates an XML element (it needs not be the document root) against a type declared in an XSD-schema.
 * 
 * @param xmlObject XML element being validated
 * @param schemas compiled XML schema(s) used for the validation
 * @param xmlObjectType Qualified name of the schema type in <code>schemas</code> against which the element validation is performed
 * @throws XmlException thrown in case of a parsing or validation error
 */
public static void validate(XmlObject xmlObject, SchemaTypeSystem schemas, QName xmlObjectType) throws XmlException {
    Node node = xmlObject.getDomNode();
    //..... some argument checking here .....

    String elemName = node.getLocalName();
    String elemNamespace = node.getNamespaceURI();
    String typeName = xmlObjectType.getLocalPart();
    String typeNamespace = xmlObjectType.getNamespaceURI();
    String schemasKey = elemName+"@"+elemNamespace +"," +typeName+"@"+typeNamespace;  //perhaps it's sufficient

    // Prepare schema
    SchemaTypeSystem loader = schemas;
    SchemaGlobalElement schemaElem = loader.findElement(new QName(elemNamespace, elemName));
    if (schemaElem != null) {
        QName elemQName = schemaElem.getType().getName();
        if (!elemQName.getLocalPart().equals(typeName) || !elemQName.getNamespaceURI().equals(typeNamespace))
            throw new IllegalArgumentException("Requested type " +typeName+"@"+typeNamespace
                    +" of xmlObject is different from its actual type " +elemQName.getLocalPart()+"@"+elemQName.getNamespaceURI() +" in provided schema(s)");
    }
    else {
        //the schema does not contain the xmlObject element declaration => add it (artificially)
        String helperSchema = ""
                + "<xs:schema attributeFormDefault=\"unqualified\" elementFormDefault=\"qualified\"\n"
                + "  targetNamespace=\"" +elemNamespace +"\"\n"
                + "  xmlns=\"" +elemNamespace +"\"\n"
                + "  xmlns:t=\"" +typeNamespace +"\"\n"
                + "  xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
                + "\n"
                + "    <xs:element name=\"" +elemName +"\" type=\"t:" +typeName +"\"/>\n"
                + "\n"
                + "</xs:schema>\n";
        loader = XmlBeans.compileXsd(schemas,  // extend the schema
                new XmlObject[]{
                        XmlObject.Factory.parse(helperSchema, new XmlOptions().setLoadLineNumbers().setLoadMessageDigest()
                                .setDocumentSourceName(schemasKey))
                }, null,
                new XmlOptions().setErrorListener(null).setCompileDownloadUrls().setCompileNoPvrRule());
    }

    // validate the element using the loader in a standard way
    // (see the link above, for instance)
    validate(xmlObject, loader);
}

我在输入上收到一个XmlObject,但通常会使用File对象。 在实现中,求助于DOM可能并不是最佳的 - 如果我更好地使用新的XmlBeans,则可以改进代码。

相关问题