/**
* Copyright (C) 2002-2012 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* FreeCol 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.common.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* A class that makes it slightly tidier to create, parse and format XML
* documents.
*/
public final class Xml
{
// ------------------------------------------------------ class API methods
public static Document newDocument() {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.newDocument();
}
catch ( ParserConfigurationException e ) {
throw new Exception( e );
}
}
public static Document documentFrom( String string ) {
return documentFrom( new InputSource(new StringReader(string)) );
}
public static Document documentFrom( InputStream stream ) {
return documentFrom( new InputSource(stream) );
}
public static String toString( Document document ) {
return document.getDocumentElement().toString();
}
public static boolean hasAttribute( Node xmlElement, String attributeName ) {
return xmlElement.getAttributes().getNamedItem(attributeName) != null;
}
public static String attribute( Node xmlElement, String attributeName ) {
return xmlElement.getAttributes().getNamedItem(attributeName).getNodeValue();
}
public static String attribute( Node xmlElement, String attributeName, String otherwise ) {
if (hasAttribute(xmlElement, attributeName)) {
return attribute(xmlElement, attributeName);
} else {
return otherwise;
}
}
public static String[] arrayAttribute( Node xmlElement, String attributeName, String separator ) {
return attribute(xmlElement, attributeName).split(separator);
}
public static String[] arrayAttribute( Node xmlElement, String attributeName ) {
return arrayAttribute(xmlElement, attributeName, ",");
}
public static String[] arrayAttribute( Node xmlElement, String attributeName, String[] otherwise ) {
if (hasAttribute(xmlElement, attributeName)) {
return arrayAttribute(xmlElement, attributeName, ",");
} else {
return otherwise;
}
}
public static char charAttribute( Node xmlElement, String attributeName ) {
return attribute(xmlElement, attributeName).charAt(0);
}
public static char charAttribute( Node xmlElement, String attributeName, char otherwise ) {
if (hasAttribute(xmlElement, attributeName)) {
return charAttribute(xmlElement, attributeName);
} else {
return otherwise;
}
}
/*
public static String messageAttribute( Node xmlElement, String attributeName ) {
return Messages.message( attribute(xmlElement, attributeName) );
}
*/
public static float floatAttribute( Node xmlElement, String attributeName ) {
return Float.parseFloat( attribute(xmlElement, attributeName) );
}
public static float floatAttribute( Node xmlElement, String attributeName, float otherwise ) {
if (hasAttribute(xmlElement, attributeName)) {
return floatAttribute(xmlElement, attributeName);
} else {
return otherwise;
}
}
public static float[] floatArrayAttribute( Node xmlElement, String attributeName, String separator ) {
String[] array = arrayAttribute(xmlElement, attributeName, separator);
float[] output = new float[array.length];
for (int i = 0; i < array.length ; i++) {
output[i] = Float.parseFloat(array[i]);
}
return output;
}
public static float[] floatArrayAttribute( Node xmlElement, String attributeName ) {
return floatArrayAttribute(xmlElement, attributeName, ",");
}
public static float[] floatArrayAttribute( Node xmlElement, String attributeName, float[] otherwise ) {
if (hasAttribute(xmlElement, attributeName)) {
return floatArrayAttribute(xmlElement, attributeName, ",");
} else {
return otherwise;
}
}
public static int intAttribute( Node xmlElement, String attributeName ) {
return Integer.parseInt( attribute(xmlElement, attributeName) );
}
public static int intAttribute( Node xmlElement, String attributeName, int otherwise ) {
if (hasAttribute(xmlElement, attributeName)) {
return intAttribute(xmlElement, attributeName);
} else {
return otherwise;
}
}
public static int[] intArrayAttribute( Node xmlElement, String attributeName, String separator ) {
String[] array = arrayAttribute(xmlElement, attributeName, separator);
/* For testing
for (int k = 0; k < array.length; k++)
logger.info(array[k]);
*/
int[] output = new int[array.length];
for (int i = 0; i < array.length ; i++) {
output[i] = Integer.parseInt(array[i]);
}
return output;
}
public static int[] intArrayAttribute( Node xmlElement, String attributeName ) {
return intArrayAttribute(xmlElement, attributeName, ",");
}
public static int[] intArrayAttribute( Node xmlElement, String attributeName, int[] otherwise ) {
if (hasAttribute(xmlElement, attributeName)) {
return intArrayAttribute(xmlElement, attributeName, ",");
} else {
return otherwise;
}
}
public static boolean booleanAttribute( Node xmlElement, String attributeName ) {
return parseTruth( attribute(xmlElement, attributeName) );
}
public static boolean booleanAttribute( Node xmlElement, String attributeName, boolean otherwise ) {
if (hasAttribute(xmlElement, attributeName)) {
return booleanAttribute(xmlElement, attributeName);
} else {
return otherwise;
}
}
public static void forEachChild( Node xml, Method method ) {
NodeList childList = xml.getChildNodes();
for ( int ci = 0, nc = childList.getLength(); ci < nc; ci ++ ) {
Node child = childList.item( ci );
if ( child instanceof Element ) {
method.invokeOn( child );
}
}
}
// -------------------------------------------------- class support methods
private static Document documentFrom( InputSource source ) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse( source );
}
catch ( ParserConfigurationException e ) {
throw new Exception( e );
}
catch ( SAXException e ) {
throw new Exception( e );
}
catch ( IOException e ) {
throw new Exception( e );
}
}
private static boolean parseTruth( String truthAsString )
{
if ( "yes".equals(truthAsString) ||
"true".equals(truthAsString) ) {
return true;
}
else if ( "no".equals(truthAsString) ) {
return false;
}
throw new RuntimeException( "mus be 'yes' or 'no': " + truthAsString );
}
// ----------------------------------------------------------- constructors
private Xml() {
}
// ----------------------------------------------------------- nested types
public interface Method {
public void invokeOn( Node xml );
}
/**
* This class is defined so that exceptions thrown by methods on {@link Xml}
* may be filtered from other runtime exceptions such as
* {@link NullPointerException} if desired. In the majority of cases, an
* exception will mean that the game cannot proceed, which is why this is a
* runtime exception so that it percolates up to the {@link Thread#run()}
* method of the invoking thread or other controlling loop without the need
* for every other method on the way to declare "throws" clauses.
*/
public static final class Exception extends RuntimeException {
Exception( Throwable cause ) {
super( cause );
}
}
}