/**
* This file is part of JSurveyLib.
*
* JSurveyLib 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.
*
* JSurveyLib 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 JSurveyLib. If not, see <http://www.gnu.org/licenses/>.
**/
package org.jsurveylib.utils;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
/**
* <u><b><font color="red">FOR INTERNAL USE ONLY.</font></b></u>
*/
public class XMLUtil {
private static final String ANSWERS_TAG = "answers";
private static final String ANSWER_TAG = "answer";
private static final String ID_TAG = "id";
private static final String QA_TAG = "qa";
private XMLUtil() {
}
private static Element parseXML(Reader input, ErrorHandler errorHandler) throws ParserConfigurationException, IOException, SAXException {
try {
//prepare parser
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
dbFactory.setIgnoringComments(true);
dbFactory.setNamespaceAware(errorHandler != null);
dbFactory.setValidating(errorHandler != null);
if (errorHandler != null) {
dbFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
}
DocumentBuilder builder = dbFactory.newDocumentBuilder();
if (errorHandler != null) {
builder.setErrorHandler(errorHandler);
}
//parse the xml file
org.w3c.dom.Document xmlDocument = builder.parse(new InputSource(input));
//extract root
return xmlDocument.getDocumentElement();
} finally {
if (input != null) {
input.close();
}
}
}
/**
* Validates the XML by the XSD it finds in the XML. You must pass in an error handler or null if you want to use a standard error handler that
* throws all exceptions.
*
* @param input The Reader of the XML file. This will be closed after it is used.
* @param errorHandler The error handler to use if an error occurs. If you pass in null, a standard error handler is used that throws all exceptions.
* @throws IOException If an error occurs reading the file.
* @throws ParserConfigurationException If an error occurs parsing the file.
* @throws SAXException If a SAX exception occurs.
*/
public static void validateXML(Reader input, ErrorHandler errorHandler) throws IOException, ParserConfigurationException, SAXException {
try {
parseXML(input, errorHandler == null ? new StandardErrorHandler() : errorHandler);
} finally {
if (input != null) {
input.close();
}
}
}
/**
* Gets the XML root element from the Reader and returns it. No validation occurs. Note that the reader is closed at the end of this method.
*
* @param input The Reader of the XML file. This will be closed after it is used.
* @return The root element of the XML file.
* @throws IOException If an error occurs reading the file.
* @throws SAXException If a SAX exception occurs.
*/
public static Element getXMLRoot(Reader input) throws SAXException, IOException {
try {
return parseXML(input, null);
} catch (ParserConfigurationException e) {
e.printStackTrace();
return null;
} finally {
if (input != null) {
input.close();
}
}
}
public static Map<String, String> getAnswerMapFromElement(Element element) {
Map<String, String> answerMap = new HashMap<String, String>();
if (isNoAnswersTag(element)) {
return answerMap;
}
validateAnswerElement(element);
NodeList qas = getQAList(element);
for (int i = 0; i < qas.getLength(); ++i) {
Element qa = (Element) qas.item(i);
String id = qa.getAttribute(ID_TAG);
String answer = qa.getElementsByTagName(ANSWER_TAG).item(0).getTextContent();
answerMap.put(id, answer);
}
return answerMap;
}
private static boolean isNoAnswersTag(Element element) {
return getAnswersTag(element) == null;
}
private static Element getAnswersTag(Element element) {
if (element.getElementsByTagName(ANSWERS_TAG).getLength() == 1) {
return (Element) element.getElementsByTagName(ANSWERS_TAG).item(0);
} else if (element.getNodeName().equals(ANSWERS_TAG)) {
return element;
} else {
return null;
}
}
private static void validateAnswerElement(Element element) {
if (element.getElementsByTagName(ANSWERS_TAG).getLength() > 1) {
throw new IllegalArgumentException("There are more than one \"answers\" tags in this element: " + element);
}
NodeList qas = getQAList(element);
for (int i = 0; i < qas.getLength(); ++i) {
Element qa = (Element) qas.item(i);
if (!qa.hasAttribute(ID_TAG)) {
throw new IllegalArgumentException("This QA tag does not have an id attribute: " + qa);
}
if (qa.getElementsByTagName(ANSWER_TAG).getLength() != 1) {
throw new IllegalArgumentException("This QA tag does not have an answer tag: " + qa);
}
}
}
private static NodeList getQAList(Element element) {
return getAnswersTag(element).getElementsByTagName(QA_TAG);
}
private static class StandardErrorHandler implements ErrorHandler {
public void warning(SAXParseException exception) throws SAXException {
throw exception;
}
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
}
/**
* Serializes an Element, and returns it back in form of string.
*
* @param element The element to serialize
* @return The element in String form.
* @throws IOException If an error occurs while serializing
*/
public static String elementToString(Element element) throws IOException {
StringWriter writer = new StringWriter();
OutputFormat format = new OutputFormat();
format.setOmitXMLDeclaration(true);
XMLSerializer serializer = new XMLSerializer(writer, format);
serializer.serialize(element);
return writer.toString();
}
}