How should I use line number and column number to get element in XML in JAVA

泄露秘密 提交于 2019-12-24 08:11:11

问题


Hi I am using JAXB and Marshal/Unmarshal Schema Validation. I have a XML file and XSD schema for validation. Code are like this:

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);
}

Some of the XML file is like this:

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

From the code above, I could get validate the XML is valid against the XSD. The logger file is something like this:

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

The validation is correct and in the xml file, the value of PortalID is not valid against the XSD schema, and the log file can tell me the location is "lineNumber 5 and ColumNumber 41" which is exactly the place for PortalID.

But what I want is to use this lineNumber 5 and ColumNumber 41 to printout that the element PortalID in the XML is not valid. Is there any way to do that? Thank you so much!


回答1:


To get the name of the last element parsed you could put a custom ContentHandler that records the last element between the SAXParser and the JAXB handler.

To do that you must use a SAXSource and create a custom XMLFilter implementation extending XMLFilterImpl

  1. pass a SAXSource to the Unmarshaller instead than a File and in the SAXSource configure an XMLReader. This is explained in Unmarshalling from a javax.xml.transform.sax.SAXSource using a client specified validating SAX2.0 parser
  2. Do not configure the SAXSource with the "real" XMLReader implementation as in Javadoc linked code but use the custom XMLFilter that wraps the "real" 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")));
    
  3. The custom filter RecordingXMLFilter could be:

    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);
    }
    }
    
  4. In exception handling code use xmlFilter.lastElement to get the QName of the last element parsed.

BTW To get line numbers do in this way, messages could be different in different locales or change between versions.

    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);

        }
    }


来源:https://stackoverflow.com/questions/41225724/how-should-i-use-line-number-and-column-number-to-get-element-in-xml-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!