我应该如何使用行号和列号在JAVA中获取XML中的元素

时间:2016-12-19 15:16:38

标签: java xml validation xsd jaxb

您好我正在使用JAXB和Marshal / Unmarshal Schema验证。我有一个XML文件和XSD架构用于验证。代码是这样的:

Validation.java

try{
    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = sf.newSchema(new File("./src/main/resources/validation.xsd"));
    JAXBContext jc = JAXBContext.newInstance(AddCustomer.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    unmarshaller.setSchema(schema);
    unmarshaller.setEventHandler(new MyValidationEventHandler());
    AddCustomer addCustomer_Validation= (AddCustomer) unmarshaller.unmarshal(new File("./src/main/resources/AddCustomer.xml"));
    logger.info("AddCustomer passed validation.");
} catch(UnmarshalException ex) {
    logger.info("linked ex: " + ex.getLinkedException().toString());
    String str = ex.getLinkedException().toString();
    int lineNumberIndex = str.indexOf("lineNumber:");
    int lineNumber = Integer.parseInt(str.substring(lineNumberIndex+12,lineNumberIndex+13));
    logger.info("lineNumber:" +lineNumber);
    int columnIndex = str.indexOf("columnNumber:");
    int columNumber = Integer.parseInt(str.substring(columnIndex+14,columnIndex+16));
    logger.info("columnNumber: " + columNumber);
}

某些XML文件是这样的:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AddCustomer xmlns="http://...">
<Customer>
    <DirectoryInformation>
        <PortalID>32        4   5</PortalID>
        <AccountID>2732</AccountID>

从上面的代码中,我可以验证XML对XSD是否有效。记录器文件是这样的:

INFO [main] Validation- linked ex: org.xml.sax.SAXParseException; systemId: file:/C:.../src/main/resources/AddCustomer.xml; lineNumber: 5; columnNumber: 41; cvc-pattern-valid: Value '32       4   5' is not facet-valid with respect to pattern '[ !-~]*' for type 'an..35'.
INFO [main] Validation- lineNumber: 5
INFO [main] Validation- columnNumber: 41

验证是正确的,在xml文件中,PortalID的值对XSD架构无效,日志文件可以告诉我位置是“lineNumber 5和ColumNumber 41”,这正是PortalID的位置。

但我想要的是使用此 lineNumber 5和ColumNumber 41 打印输出XML中的元素 PortalID 无效。有没有办法做到这一点? 非常感谢你!

1 个答案:

答案 0 :(得分:0)

要获取解析的最后一个元素的名称,可以放置一个自定义ContentHandler,记录SAXParser和JAXB处理程序之间的最后一个元素。

为此,您必须使用SAXSource并创建扩展XMLFilter的自定义XMLFilterImpl实施

  1. SAXSource传递给Unmarshaller而不是File,并SAXSource配置XMLReader。这在Unmarshalling from a javax.xml.transform.sax.SAXSource using a client specified validating SAX2.0 parser
  2. 中有解释
  3. 请勿使用&#34; real&#34;配置SAXSource {JACadoc链接代码中的XMLReader实现,但使用包含&#34; real&#34;的自定义XMLFilter。 XMLReader

       XMLReader xmlReader = saxParser.getXMLReader();
       RecordingXMLFilter xmlFilter = new RecordingXMLFilter(xmlReader);
       SAXSource source =
       new SAXSource(xmlFilter, new InputSource(new FileInputStream(new File("./src/main/resources/AddCustomer.xml")));
    
  4. 自定义过滤器RecordingXMLFilter可以是:

    private static final class RecordingXMLFilter extends XMLFilterImpl
    {
    
    String lastElement;
    
    private RecordingXMLFilter(XMLReader parent)
    {
        super(parent);
    }
    
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    {
        lastElement = qName;
        super.startElement(uri, localName, qName, attributes);
    }
    }
    
  5. 在异常处理代码中使用xmlFilter.lastElement来获取解析的最后一个元素的QName。
  6. BTW要以这种方式获取行号,消息可能在不同的语言环境中有所不同,或者在不同版本之间发生变化。

        try
        {
            ..........
        }
        catch(UnmarshalException ex) {
            Throwable linked = ex.getLinkedException();
            if (linked instanceof SAXParseException)
            {
                SAXParseException t = (SAXParseException) linked;
                int lineNumber = t.getLineNumber();
                int columNumber = t.getColumnNumber();
                logger.info("lineNumber:" +lineNumber);
                logger.info("columnNumber: " + columNumber);
    
            }
        }