2016-02-05 28 views
1

在標準Java環境中針對xsd模式驗證xml源時,我無法找到獲取有關未通過驗證的元素(在許多特定情況下)的信息的方法。如何在SAXParseException中獲取XML元素信息

當捕獲一個SAXParseException時,元素的信息消失了。但是,在調試到xerces.XmlSchemaValidator時,我可以看到原因是沒有定義特定的錯誤消息來提供有關該元素的信息。

例如(我的java演示中也是這種情況)「cvc -mininclusive-valid」錯誤是這樣定義的: cvc-minInclusive-valid:值''{0}''不是facet對於類型「{2}」,minInclusive''{1}''有效。 https://wiki.xmldation.com/Support/Validator/cvc-mininclusive-valid

什麼我寧願是,這樣的信息將被產生: CVC-type.3.1.3:該值「」 {1}「」元素「的」 {0}「」是無效。 https://wiki.xmldation.com/Support/Validator/cvc-type-3-1-3

當調試到xerces.XMLSchemaValidator時,我可以看到有兩個連續的調用reportSchemaError(...) - 第二個只發生,如果第一個沒有引發異常返回。

有什麼辦法可以配置驗證器使用第二種報告方式或用元素信息豐富SAXParseException嗎?

請參閱我複製&粘貼&可運行下面的例子代碼作進一步的解釋:

String xsd = 
      "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + 
        "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" version=\"1.0\">" + 
        "<xs:element name=\"demo\">" + 
        "<xs:complexType>" + 
        "<xs:sequence>" + 

        // given are two elements that cannot be < 1 
        "<xs:element name=\"foo\" type=\"xs:positiveInteger\" minOccurs=\"0\" maxOccurs=\"unbounded\" />" + 
        "<xs:element name=\"bar\" type=\"xs:positiveInteger\" minOccurs=\"0\" maxOccurs=\"unbounded\" />" + 

        "</xs:sequence>" + 
        "</xs:complexType>" + 
        "</xs:element>" + 
        "</xs:schema>"; 

    String xml = 
      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
        "<demo>" + 

        "<foo>1</foo>" + 
        // invalid! 
        "<foo>0</foo>" + 
        "<bar>2</bar>" + 

        "</demo>"; 

    Validator validator = SchemaFactory 
      .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) 
      .newSchema(new StreamSource(new StringReader(xsd))) 
      .newValidator(); 


    try { 
     validator.validate(new StreamSource(new StringReader(xml))); 
    } catch (SAXParseException e) { 

     // unfortunately no element or line/column info: 
     System.err.println(e.getMessage()); 

     // better, but still no element info: 
     System.err.println(String.format("Line %s - Column %s - %s", 
       e.getLineNumber(), 
       e.getColumnNumber(), 
       e.getMessage())); 
    } 
+0

不幸的是,我不認爲這是可能的。如果您必須具有元素名稱,則可以編寫自己的代碼以根據行號和列號找到元素名稱,但即使如此,我也不認爲這些元素始終保證可靠。 – Matthew

+0

感謝您的評論,@Matthew!我會給我的問題多一點時間,直到我失去希望,你是對的:) – realsim

回答

1

嘗試使用錯誤處理:

public class LoggingErrorHandler implements ErrorHandler { 

    private boolean isValid = true; 

    public boolean isValid() { 
     return this.isValid; 
    } 

    @Override 
    public void warning(SAXParseException exc) { 
     System.err.println(exc); 
    } 

    @Override 
    public void error(SAXParseException exc) { 
     System.err.println(exc); 
     this.isValid = false; 
    } 

    @Override 
    public void fatalError(SAXParseException exc) throws SAXParseException { 
     System.err.println(exc); 
     this.isValid = false; 
     throw exc; 
    } 
} 

,並驗證使用它:

 Validator validator = SchemaFactory 
       .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) 
       .newSchema(new StreamSource(new StringReader(xsd))) 
       .newValidator(); 
     LoggingErrorHandler errorHandler = new LoggingErrorHandler(); 
     validator.setErrorHandler(errorHandler); 
     validator.validate(new StreamSource(new StringReader(xml))); 
     return errorHandler.isValid(); 
2

這沒有很好的記錄,但如果您有近期版本的Xerces-J(請參閱SVN Rev 380997),您可以驗證DOMSource並從ErrorHandler查詢Validator以檢索驗證程序在報告時正在處理的當前Element節點錯誤。

例如,你可以寫一個ErrorHandler像:

public class ValidatorErrorHandler implements ErrorHandler { 

private Validator validator; 

public ValidatorErrorHandler(Validator v) { 
    validator = v; 
} 

... 

public void error(SAXParseException spe) throws SAXException { 
    Node node = null; 
    try { 
     node = (Node) 
      validator.getProperty(
       "http://apache.org/xml/properties/dom/current-element-node"); 
    } 
    catch (SAXException se) {} 
    ... 
} 

,然後調用Validator與此類似ErrorHandler

Validator validator = SchemaFactory 
     .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) 
     .newSchema(new StreamSource(new StringReader(xsd))) 
     .newValidator(); 
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
dbf.setNamespaceAware(true); 
DocumentBuilder db = dbf.newDocumentBuilder(); 
Document doc = db.parse(new InputSource(new StringReader(xml)); 
ErrorHandler errorHandler = new ValidatorErrorHandler(validator); 
validator.setErrorHandler(errorHandler); 
validator.validate(new DOMSource(doc)); 

獲得任何出錯的元素。

+0

我一定會嘗試,但有點害怕使用DOM,因爲我正在處理非常大的XML。目前一切都基於我的環境中的SAX。 – realsim