使用ONLY根XSD(Java)验证XML

时间:2015-02-15 15:34:16

标签: java xml validation xsd

我继续寻找可以帮助我的东西,但没有成功,所以我转向你。

我正在编写一个Java代码,需要根据给定的动态模式验证XML。我给了2个XSD,其中一个引用了另一个的元素。 要求是使用根XSD中的元素的XML将是有效的。一个例子可以解决问题。

XSD示例

第一个:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://root/beer" 
        xmlns="http://root/beer" xmlns:chl="http://child/earth"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:import namespace="http://child/earth" schemaLocation="testing_child.xsd"/>

<xs:element name="head">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="chl:banana"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

第二个:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://child/earth"
        xmlns="http://child/earth"  elementFormDefault="qualified"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="banana">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="leaf" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

现在,我希望以下XML有效:

<head xmlns="http://root/beer">
 <banana xmlns="http://child/earth">
    <leaf>yo</leaf>
 </banana>
</head>

但是(这是棘手的一点),这个不会:

<banana xmlns="http://child/earth">
    <leaf>yo</leaf>
</banana>

我尝试使用带有SAX和DOM的Validator,使用LSResourceResolver和没有,但得到了相同的结果 - 两个XML都是有效的,而不仅仅是父(/ root).... 我无法使用JAXB,因为我无法在XSD中构建类(它们保存在fs中的文件中)。 不,我也无法改变XSD。

如果您知道某种方式/过去做过类似事情并且可以帮助我,我会非常感激。

由于

2 个答案:

答案 0 :(得分:0)

由于这显然符合XML Schema,因此没有合规验证者应该抱怨banana作为顶级元素。

所以你需要一些额外的东西。

我最初考虑通过资源解析器中的临时处理使banana成为一个抽象元素。但是banana作为非根元素可能有效用法(例如,通过xs:element/@ref)。

所以我建议做一些额外的验证 - 或者通过像Schematron这样的东西或只是#34;用Java编写自己的#34;

你可能在Java中使用Xerces。

  • 您可以进入Schema对象,找出顶级元素及其位置。
  • 然后你可以收集那些位于&#34; root&#34;中的元素的QName。架构。
  • 最后,您只需根据该集检查文档元素的QName。

我就是这样做的。这将使您与验证器实现联系起来,但无论如何您的自定义都是专有的。

答案 1 :(得分:0)

正如@lexicore建议的那样,我添加了额外的验证代码(不是我写的最漂亮的东西,但它现在有用)。

如果有人提出异议:

public static void validate(String fileLocXSD, String fileLocXML) {
     try {
         boolean valid = false;

         // Read data to strings 
         String xsd = dataFromFile(fileLocXSD);
         xsd = xsd.toLowerCase();
         String xml = dataFromFile(fileLocXML);
         xml = xml.toLowerCase();

         // Notice that parsing errors may occure 
         Document doc = getDocument(xsd);
         Document docXML = getDocument(xml); 

         // Let's strip down the xsd and get what we want 
         ArrayList<String> listHeaders = new ArrayList<String>();  
         Element docElement = doc.getDocumentElement();
         NodeList listElements = docElement.getChildNodes();

         String ns = docElement.getAttribute("targetnamespace");
         ns = ns==null?"":ns;

         // Check all child elements of the doc element
         for (int i=0; i<listElements.getLength(); i++) {

             Node node = listElements.item(i);

             if (node.getNodeName().contains("element")) {
                 listHeaders.add(((Element)node).getAttribute("name"));
             }

         }

         // What about the xml ha? don't forget about it (or about Dre) 
         Element docXMLElement = docXML.getDocumentElement();
         String nsXML = "";
         String rootName = docXMLElement.getNodeName();

         // Default ns in xml
         if (!rootName.contains(":")) {

             nsXML = docXMLElement.getAttribute("xmlns");
             nsXML = nsXML==null?"":nsXML;

             // No namespace
             if (("").equals(ns) && ("").equals(nsXML)) {

                 for (int j=0; (j<listHeaders.size()) && (!valid); j++) {
                     if (listHeaders.get(j).equals(rootName)) {
                         valid = true;
                     }
                 }

             } else if ((ns).equals(nsXML)) {

                 for (int j=0; (j<listHeaders.size()) && (!valid); j++) {
                     if (listHeaders.get(j).equals(rootName)) {
                         valid = true;
                     }
                 }
             }

         } else {

             String shortNS = rootName.substring(0,rootName.indexOf(":"));
             nsXML = docXMLElement.getAttribute("xmlns:"+shortNS);
             rootName = rootName.substring(rootName.indexOf(":")+1);

             // has to be namespace in xsd
             if ((ns).equals(nsXML)) {

                 for (int j=0; (j<listHeaders.size()) && (!valid); j++) {
                     if (listHeaders.get(j).equals(rootName)) {
                         valid = true;
                     }
                 }
             } 
         }

         System.out.println(valid?"valid":"nope");  

     }  catch (SAXParseException e) {
         System.out.println("Parsing error: "+e.getMessage());
     }catch (Exception e) {
         System.out.println("holy shit: "+e.getMessage());
     }
 }

 public static String dataFromFile(String fileLoc) {

     String xml = "";
     try {
         BufferedReader b = new BufferedReader(new InputStreamReader(new FileInputStream(fileLoc),"UTF-8")); 
         StringBuilder builder = new StringBuilder();
         String line = null;
         while((line = b.readLine()) != null) {                
             builder.append(line);
         } 
         xml = builder.toString();
         xml = xml.trim().replaceFirst("^([\\W]+)<","<");
     } catch (Exception e) {
         System.err.println("Error reading file");
     }
     return xml;
 }

 public static Document getDocument(String xml) throws Exception {
     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
     factory.setNamespaceAware(false);
     factory.setValidating(false);
     DocumentBuilder builder = factory.newDocumentBuilder();
     Document doc = builder.parse(new InputSource(new StringReader(xml)));
     return doc;
 }