Use dom4j to locate the node with line number

I used dom4j to parse a xml file and I got a document with line numbers, I want to use the line numbers to locate all nodes with line numbers and to operate these nodes.

Is there a way to use dom4j or other DOM API to implement this?

Answers


It is possible to extend DOM4J to include line numbers for element, but it is a bit convoulted, and not 100% exact (you can get the line number of the ">" character of the opening element).

Probably, a much more robust approach would be to report an XPath expression for each of the offending elements, and then use these expressions to fix it.

However, just for fun, here is a complete example of how to include line number information in DOM4J:

public class LineNumber {

    public static void main(String[] args) throws Exception {

        SAXReader reader = new MySAXReader();
        reader.setDocumentFactory(new LocatorAwareDocumentFactory());

        Document doc = reader
                .read(new StringReader("<root foo='bar' > \n<alfa/>\n<beta/>\n<gamma/>\n</root>\n"));
        doc.accept(new VisitorSupport() {
            @Override
            public void visit(Element node) {
                System.out.printf("%d: %s\n",
                        ((LocationAwareElement) node).getLineNumber(),
                        node.getName());
            }
        });

    }

    static class MySAXReader extends SAXReader {

        @Override
        protected SAXContentHandler createContentHandler(XMLReader reader) {
            return new MySAXContentHandler(getDocumentFactory(),
                    getDispatchHandler());
        }

        @Override
        public void setDocumentFactory(DocumentFactory documentFactory) {
            super.setDocumentFactory(documentFactory);
        }

    }

    static class MySAXContentHandler extends SAXContentHandler {

        private Locator locator;

        // this is already in SAXContentHandler, but private
        private DocumentFactory documentFactory;

        public MySAXContentHandler(DocumentFactory documentFactory,
                ElementHandler elementHandler) {
            super(documentFactory, elementHandler);
            this.documentFactory = documentFactory;
        }

        @Override
        public void setDocumentLocator(Locator documentLocator) {
            super.setDocumentLocator(documentLocator);
            this.locator = documentLocator;
            if (documentFactory instanceof LocatorAwareDocumentFactory) {
                ((LocatorAwareDocumentFactory)documentFactory).setLocator(documentLocator);
            }

        }

        public Locator getLocator() {
            return locator;
        }
    }

    static class LocatorAwareDocumentFactory extends DocumentFactory {

        private Locator locator;

        public LocatorAwareDocumentFactory() {
            super();
        }

        public void setLocator(Locator locator) {
            this.locator = locator;
        }

        @Override
        public Element createElement(QName qname) {
            LocationAwareElement element = new LocationAwareElement(qname);
            if (locator != null)
                element.setLineNumber(locator.getLineNumber());
            return element;
        }

    }

    /**
     * An Element that is aware of it location (line number in) in the source document
     */
    static class LocationAwareElement extends DefaultElement {

        private int lineNumber = -1;

        public LocationAwareElement(QName qname) {
            super(qname);
        }

        public LocationAwareElement(QName qname, int attributeCount) {
            super(qname, attributeCount);

        }

        public LocationAwareElement(String name, Namespace namespace) {
            super(name, namespace);

        }

        public LocationAwareElement(String name) {
            super(name);

        }

        public int getLineNumber() {
            return lineNumber;
        }

        public void setLineNumber(int lineNumber) {
            this.lineNumber = lineNumber;
        }

    }

}

Your checker could set an attribute in your node, to flag it for fixing. This would be an alternative for reading the file lines. Afterwards just look for nodes with this specific attribute and refactor it.

<?xml version="1.0" encoding="UTF-8"?>
<tests>
    <test>okay</test>
    <test>good</test>
    <test>error</test>
</tests>

now parse the xml file and mark the last test node to be fixed

public void parse(){

    SAXReader reader = new SAXReader();
    DocumentFactory documentFactory = DocumentFactory.getInstance();
    Document document = reader.read("test.xml");
    Element root = document.getRootElement();

    for (Iterator<Element> iterator = root.elementIterator();iterator.hasNext();){
        Element element = iterator.next();

        //check for your error and set fix flag, if not already happend 

        if(element.getText().equals("error") && 
           element.attributeValue("todo") == null) {

           Attribute fix = documentFactory.createAttribute(element, "todo" ,"fix");
            element.add(fix);
        }
    }

    // update xml file

    XMLWriter xmlWriter = new XMLWriter(new FileWriter("test.xml"));
    xmlWriter.write(document);
    xmlWriter.close();
}

output xml

enter <?xml version="1.0" encoding="UTF-8"?>
<tests>
    <test>okay</test>
    <test>good</test>
    <test todo="fix">error</test>
</tests>

Need Your Help

RegularExpression for the textbox which allows only certain symbols

javascript regex

I have a text box.In my text box I should enter the age Range as numbers.

UITableView display multi image

ios uitableview

How can I display multi-image in UITableView?