org.sonar.api.utils.XpathParser.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.api.utils.XpathParser.java

Source

/*
 * Sonar, open source software quality management tool.
 * Copyright (C) 2008-2012 SonarSource
 * mailto:contact AT sonarsource DOT com
 *
 * Sonar is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * Sonar is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Sonar; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonar.api.utils;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;

/**
 * XML Parsing tool using XPATH. It's recommended to use StaxParser when parsing big XML files.
 *
 * @since 1.10
 */
public class XpathParser {

    private Element root = null;
    private Document doc = null;
    private DocumentBuilder builder;
    private XPath xpath;
    private Map<String, XPathExpression> compiledExprs = new HashMap<String, XPathExpression>();

    public XpathParser() {
        DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
        try {
            bf.setFeature("http://apache.org/xml/features/validation/schema", false);
            bf.setFeature("http://xml.org/sax/features/external-general-entities", false);
            bf.setFeature("http://xml.org/sax/features/validation", false);
            bf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
            bf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            bf.setFeature("http://apache.org/xml/features/allow-java-encodings", true);
        } catch (ParserConfigurationException e) {
            Logger log = LoggerFactory.getLogger(this.getClass().getName());
            log.error("Error occured during features set up.", e);
        }
        try {
            bf.setNamespaceAware(false);
            bf.setValidating(false);
            builder = bf.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new XmlParserException("can not create a XML parser", e);
        }
    }

    public void parse(File file) {
        if (file == null || !file.exists()) {
            throw new XmlParserException("File not found : " + file);
        }

        BufferedReader buffer = null;
        try {
            buffer = new BufferedReader(new FileReader(file));
            parse(buffer);

        } catch (IOException e) {
            throw new XmlParserException("can not parse the file " + file.getAbsolutePath(), e);

        } finally {
            IOUtils.closeQuietly(buffer);
        }
    }

    public void parse(InputStream stream) {
        BufferedReader buffer = null;
        try {
            buffer = new BufferedReader(new InputStreamReader(stream));
            parse(buffer);

        } catch (IOException e) {
            throw new XmlParserException("can not parse the stream", e);

        } finally {
            IOUtils.closeQuietly(buffer);
        }
    }

    private void parse(BufferedReader buffer) throws IOException {
        parse(IOUtils.toString(buffer));
    }

    public void parse(String xml) {
        try {
            xml = fixUnicodeChar(xml);
            doc = builder.parse(new ByteArrayInputStream(xml.getBytes()));
            XPathFactory factory = XPathFactory.newInstance();
            xpath = factory.newXPath();

        } catch (SAXException e) {
            throw new XmlParserException("can not parse xml : " + xml, e);
        } catch (IOException e) {
            throw new XmlParserException("can not parse xml : " + xml, e);
        }
    }

    public Element getRoot() {
        if (root == null && doc != null) {
            root = doc.getDocumentElement();
        }
        return root;
    }

    public Document getDocument() {
        return doc;
    }

    public Element getChildElement(Element base, String elementName) {
        NodeList childrens = base.getElementsByTagName(elementName);
        for (int i = 0; i < childrens.getLength(); i++) {
            Node nde = childrens.item(i);
            if (nde.getNodeType() == Node.ELEMENT_NODE) {
                return (Element) nde;
            }
        }
        return null;
    }

    public Element getChildElement(String elementName) {
        NodeList childrens = getRoot().getElementsByTagName(elementName);
        for (int i = 0; i < childrens.getLength(); i++) {
            Node nde = childrens.item(i);
            if (nde.getNodeType() == Node.ELEMENT_NODE) {
                return (Element) nde;
            }
        }
        return null;
    }

    public List<Element> getChildElements(String elementName) {
        List<Element> rtrVal = new ArrayList<Element>();
        NodeList childrens = getRoot().getElementsByTagName(elementName);
        for (int i = 0; i < childrens.getLength(); i++) {
            Node nde = childrens.item(i);
            if (nde.getNodeType() == Node.ELEMENT_NODE) {
                rtrVal.add((Element) nde);
            }
        }
        return rtrVal;
    }

    public List<Element> getChildElements(Element base, String elementName) {
        List<Element> rtrVal = new ArrayList<Element>();
        NodeList childrens = base.getElementsByTagName(elementName);
        for (int i = 0; i < childrens.getLength(); i++) {
            Node nde = childrens.item(i);
            if (nde.getNodeType() == Node.ELEMENT_NODE) {
                rtrVal.add((Element) nde);
            }
        }
        return rtrVal;
    }

    public String getChildElementValue(Element base, String elementName) {
        NodeList childrens = base.getElementsByTagName(elementName);
        for (int i = 0; i < childrens.getLength(); i++) {
            if (childrens.item(i).getNodeType() == Node.ELEMENT_NODE) {
                return childrens.item(i).getFirstChild().getNodeValue();
            }
        }
        return null;
    }

    public String getElementValue(Node base) {
        if (base.getNextSibling() != null && base.getNextSibling().getNodeType() == Node.TEXT_NODE) {
            return base.getNextSibling().getNodeValue();
        } else if (base.getFirstChild() != null && base.getFirstChild().getNodeType() == Node.TEXT_NODE) {
            return base.getFirstChild().getNodeValue();
        }
        return null;
    }

    public String getChildElementValue(String elementName) {
        NodeList childrens = getRoot().getElementsByTagName(elementName);
        for (int i = 0; i < childrens.getLength(); i++) {
            if (childrens.item(i).getNodeType() == Node.ELEMENT_NODE) {
                return childrens.item(i).getFirstChild().getNodeValue();
            }
        }
        return null;
    }

    public Object executeXPath(Node node, QName qname, String xPathExpression) {
        XPathExpression expr = compiledExprs.get(xPathExpression);
        try {
            if (expr == null) {
                expr = xpath.compile(xPathExpression);
                compiledExprs.put(xPathExpression, expr);
            }
            return expr.evaluate(node, qname);

        } catch (XPathExpressionException e) {
            throw new XmlParserException("Unable to evaluate xpath expression :" + xPathExpression, e);
        }
    }

    public String executeXPath(String xPathExpression) {
        return (String) executeXPath(doc, XPathConstants.STRING, xPathExpression);
    }

    public String executeXPath(Node node, String xPathExpression) {
        return (String) executeXPath(node, XPathConstants.STRING, xPathExpression);
    }

    public NodeList executeXPathNodeList(String xPathExpression) {
        return (NodeList) executeXPath(doc, XPathConstants.NODESET, xPathExpression);
    }

    public NodeList executeXPathNodeList(Node node, String xPathExpression) {
        return (NodeList) executeXPath(node, XPathConstants.NODESET, xPathExpression);
    }

    public Node executeXPathNode(Node node, String xPathExpression) {
        return (Node) executeXPath(node, XPathConstants.NODE, xPathExpression);
    }

    /**
     * Fix the error occured when parsing a string containing unicode character
     * Example : &u20ac; will be replaced by &#x20ac;
     */
    protected String fixUnicodeChar(String text) {
        String unicode = "&u";
        StringBuilder replace = new StringBuilder(text);
        if (text.indexOf(unicode) >= 0) {
            Pattern p = Pattern.compile("&u([0-9a-fA-F]{1,4});");
            Matcher m = p.matcher(replace.toString());
            int nbFind = 0;
            while (m.find()) {
                // Add one index each time because we add one character each time (&u -> &#x)
                replace.replace(m.start() + nbFind, m.end() + nbFind, "&#x" + m.group(1) + ";");
                nbFind++;
            }
        }
        return replace.toString();
    }
}