com.rapiddweller.common.xml.XMLUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rd-lib-common Show documentation
Show all versions of rd-lib-common Show documentation
'rapiddweller Common' is an open source Java library
forked from Databene Commons by Volker Bergmann.
It provides extensions to the Java core library by utility classes, abstract concepts
and concrete implementations.
/*
* Copyright (C) 2004-2015 Volker Bergmann ([email protected]).
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.rapiddweller.common.xml;
import com.rapiddweller.common.ArrayBuilder;
import com.rapiddweller.common.BeanUtil;
import com.rapiddweller.common.ConfigurationError;
import com.rapiddweller.common.Converter;
import com.rapiddweller.common.Encodings;
import com.rapiddweller.common.ErrorHandler;
import com.rapiddweller.common.Filter;
import com.rapiddweller.common.IOUtil;
import com.rapiddweller.common.Level;
import com.rapiddweller.common.ParseUtil;
import com.rapiddweller.common.StringUtil;
import com.rapiddweller.common.SyntaxError;
import com.rapiddweller.common.SystemInfo;
import com.rapiddweller.common.Visitor;
import com.rapiddweller.common.converter.NoOpConverter;
import com.rapiddweller.common.converter.String2DateConverter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.w3c.dom.Attr;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import org.xml.sax.EntityResolver;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* Provides XML Utility methods.
* Created: 25.08.2007 22:09:26
*
* @author Volker Bergmann
*/
public class XMLUtil {
private static final Logger LOGGER = LogManager.getLogger(XMLUtil.class);
private static final String DOCUMENT_BUILDER_FACTORY_IMPL = "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl";
private static final ErrorHandler DEFAULT_ERROR_HANDLER = new ErrorHandler(XMLUtil.class.getSimpleName(), Level.error);
private static String defaultDocumentBuilderClassName = DOCUMENT_BUILDER_FACTORY_IMPL;
private XMLUtil() {
}
/**
* Format string.
*
* @param document the document
* @return the string
*/
public static String format(Document document) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
String encoding = Encodings.UTF_8;
SimpleXMLWriter out = new SimpleXMLWriter(buffer, encoding, true);
format(document.getDocumentElement(), out);
out.close();
try {
return buffer.toString(encoding);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* Format string.
*
* @param element the element
* @return the string
*/
public static String format(Element element) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
String encoding = Encodings.UTF_8;
SimpleXMLWriter out = new SimpleXMLWriter(buffer, encoding, false);
format(element, out);
out.close();
try {
return buffer.toString(encoding);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* Format short string.
*
* @param element the element
* @return the string
*/
public static String formatShort(Element element) {
StringBuilder builder = new StringBuilder();
builder.append('<').append(element.getNodeName());
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Attr attribute = (Attr) attributes.item(i);
builder.append(' ').append(attribute.getName()).append("=\"").append(attribute.getValue()).append('"');
}
builder.append("...");
return builder.toString();
}
/**
* Format start tag string.
*
* @param element the element
* @return the string
*/
public static String formatStartTag(Element element) {
StringBuilder builder = new StringBuilder();
builder.append('<').append(element.getNodeName());
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Attr attribute = (Attr) attributes.item(i);
builder.append(' ').append(attribute.getName()).append("=\"").append(attribute.getValue()).append('"');
}
builder.append(">");
return builder.toString();
}
/**
* Local name string.
*
* @param element the element
* @return the string
*/
public static String localName(Element element) {
return localName(element.getNodeName());
}
/**
* Local name string.
*
* @param elementName the element name
* @return the string
*/
public static String localName(String elementName) {
if (elementName == null) {
return null;
}
int sep = elementName.indexOf(':');
if (sep < 0) {
return elementName;
}
return elementName.substring(sep + 1);
}
/**
* Get child elements element [ ].
*
* @param parent the parent
* @return the element [ ]
*/
public static Element[] getChildElements(Element parent) {
NodeList childNodes = parent.getChildNodes();
return toElementArray(childNodes);
}
/**
* To element array element [ ].
*
* @param nodeList the node list
* @return the element [ ]
*/
public static Element[] toElementArray(NodeList nodeList) {
if (nodeList == null) {
return new Element[0];
}
int n = nodeList.getLength();
ArrayBuilder builder = new ArrayBuilder<>(Element.class, n);
for (int i = 0; i < n; i++) {
Node item = nodeList.item(i);
if (item instanceof Element) {
builder.add((Element) item);
}
}
return builder.toArray();
}
/**
* To element list list.
*
* @param nodeList the node list
* @return the list
*/
public static List toElementList(NodeList nodeList) {
List list = new ArrayList<>(nodeList != null ? nodeList.getLength() : 0);
if (nodeList == null) {
return list;
}
int n = nodeList.getLength();
for (int i = 0; i < n; i++) {
Node item = nodeList.item(i);
if (item instanceof Element) {
list.add((Element) item);
}
}
return list;
}
/**
* Get child elements element [ ].
*
* @param parent the parent
* @param namespaceAware the namespace aware
* @param name the name
* @return the element [ ]
*/
public static Element[] getChildElements(Element parent, boolean namespaceAware, String name) {
ArrayBuilder builder = new ArrayBuilder<>(Element.class);
NodeList childNodes = parent.getChildNodes();
if (childNodes == null) {
return new Element[0];
}
int n = childNodes.getLength();
for (int i = 0; i < n; i++) {
Node item = childNodes.item(i);
if (item instanceof Element && hasName(name, namespaceAware, item)) {
builder.add((Element) item);
}
}
return builder.toArray();
}
/**
* Gets child element at path.
*
* @param parent the parent
* @param path the path
* @param namespaceAware the namespace aware
* @param required the required
* @return the child element at path
*/
public static Element getChildElementAtPath(Element parent, String path, boolean namespaceAware, boolean required) {
Element[] elements = getChildElementsAtPath(parent, path, namespaceAware);
return assertSingleSearchResult(elements, required, path);
}
/**
* Get child elements at path element [ ].
*
* @param parent the parent
* @param path the path
* @param namespaceAware the namespace aware
* @return the element [ ]
*/
public static Element[] getChildElementsAtPath(Element parent, String path, boolean namespaceAware) {
ArrayBuilder builder = new ArrayBuilder<>(Element.class);
getChildElementsAtPath(parent, namespaceAware, path.split("/"), 0, builder);
return builder.toArray();
}
private static void getChildElementsAtPath(Element parent, boolean namespaceAware, String[] pathComponents, int pathIndex,
ArrayBuilder result) {
NodeList childNodes = parent.getChildNodes();
if (childNodes != null) {
String pathComponentName = pathComponents[pathIndex];
int n = childNodes.getLength();
for (int i = 0; i < n; i++) {
Node item = childNodes.item(i);
if (item instanceof Element) {
Element element = (Element) item;
if (pathIndex < pathComponents.length - 1) {
getChildElementsAtPath(element, namespaceAware, pathComponents, pathIndex + 1, result);
} else if (hasName(pathComponentName, namespaceAware, item)) {
result.add(element);
}
}
}
}
}
/**
* Has name boolean.
*
* @param name the name
* @param namespaceAware the namespace aware
* @param item the item
* @return the boolean
*/
public static boolean hasName(String name, boolean namespaceAware, Node item) {
String fqName = item.getNodeName();
if (namespaceAware) {
return fqName.equals(name);
} else {
return name.equals(StringUtil.lastToken(fqName, ':'));
}
}
/**
* Gets child element.
*
* @param parent the parent
* @param namespaceAware the namespace aware
* @param required the required
* @param name the name
* @return the child element
*/
public static Element getChildElement(Element parent, boolean namespaceAware, boolean required, String name) {
Element[] elements = getChildElements(parent, namespaceAware, name);
return assertSingleSearchResult(elements, required, name);
}
/**
* Gets child element text.
*
* @param elem the elem
* @param namespaceAware the namespace aware
* @param required the required
* @param name the name
* @return the child element text
*/
public static String getChildElementText(Element elem, boolean namespaceAware, boolean required, String name) {
Element childElement = XMLUtil.getChildElement(elem, namespaceAware, required, name);
if (childElement == null) {
return null;
}
return childElement.getTextContent();
}
/**
* Gets child element date.
*
* @param elem the elem
* @param namespaceAware the namespace aware
* @param required the required
* @param name the name
* @param pattern the pattern
* @return the child element date
*/
public static LocalDate getChildElementDate(Element elem, boolean namespaceAware, boolean required, String name, String pattern) {
Element childElement = XMLUtil.getChildElement(elem, namespaceAware, required, name);
if (childElement == null) {
return null;
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
String dateSpec = childElement.getTextContent();
return LocalDate.parse(dateSpec, formatter);
}
/**
* Gets child element local date time.
*
* @param elem the elem
* @param namespaceAware the namespace aware
* @param required the required
* @param name the name
* @param pattern the pattern
* @return the child element local date time
*/
public static LocalDateTime getChildElementLocalDateTime(Element elem, boolean namespaceAware, boolean required, String name, String pattern) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
String dateSpec = XMLUtil.getChildElement(elem, namespaceAware, required, name).getTextContent();
return LocalDateTime.parse(dateSpec, formatter);
}
private static Element assertSingleSearchResult(Element[] elements, boolean required, String searchTerm) {
if (required && elements.length == 0) {
throw new IllegalArgumentException("No element found in search: " + searchTerm);
}
if (elements.length > 1) {
throw new IllegalArgumentException("More that one element found in search: " + searchTerm);
}
return (elements.length > 0 ? elements[0] : null);
}
/**
* Get texts string [ ].
*
* @param nodes the nodes
* @return the string [ ]
*/
public static String[] getTexts(Element[] nodes) {
if (nodes == null) {
return null;
}
String[] texts = new String[nodes.length];
for (int i = 0; i < nodes.length; i++) {
texts[i] = getText(nodes[i]);
}
return texts;
}
/**
* Gets text.
*
* @param node the node
* @return the text
*/
public static String getText(Node node) {
if (node == null) {
return null;
}
if (node instanceof Text) {
return node.getNodeValue();
}
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
if (children.item(i) instanceof Text) {
return children.item(i).getNodeValue();
}
}
return null;
}
/**
* Gets integer attribute.
*
* @param element the element
* @param name the name
* @param defaultValue the default value
* @return the integer attribute
*/
public static Integer getIntegerAttribute(Element element, String name, Integer defaultValue) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("getIntegerAttribute(" + element.getNodeName() + ", " + name + ')');
}
String stringValue = getAttribute(element, name, false);
if (StringUtil.isEmpty(stringValue)) {
return defaultValue;
}
return Integer.parseInt(stringValue);
}
/**
* Gets long attribute.
*
* @param element the element
* @param name the name
* @param defaultValue the default value
* @return the long attribute
*/
public static Long getLongAttribute(Element element, String name, long defaultValue) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("getLongAttribute(" + element.getNodeName() + ", " + name + ')');
}
String stringValue = getAttribute(element, name, false);
if (StringUtil.isEmpty(stringValue)) {
return defaultValue;
}
return Long.parseLong(stringValue);
}
/**
* Gets attribute.
*
* @param element the element
* @param attributeName the attribute name
* @param required the required
* @return the attribute
*/
public static String getAttribute(Element element, String attributeName, boolean required) {
String value = StringUtil.emptyToNull(element.getAttribute(attributeName));
if (value == null && required) {
throw new IllegalArgumentException("Element '" + element.getNodeName() + "'" +
" is missing the required attribute '" + attributeName + "'");
}
return value;
}
/**
* Gets attributes.
*
* @param element the element
* @return the attributes
*/
public static Map getAttributes(Element element) {
NamedNodeMap attributes = element.getAttributes();
Map result = new HashMap<>();
int n = attributes.getLength();
for (int i = 0; i < n; i++) {
Attr attribute = (Attr) attributes.item(i);
result.put(attribute.getName(), attribute.getValue());
}
return result;
}
/**
* Create xml file print writer.
*
* @param uri the uri
* @param encoding the encoding
* @return the print writer
* @throws FileNotFoundException the file not found exception
* @throws UnsupportedEncodingException the unsupported encoding exception
*/
public static PrintWriter createXMLFile(String uri, String encoding)
throws FileNotFoundException, UnsupportedEncodingException {
PrintWriter printer = IOUtil.getPrinterForURI(uri, encoding);
printer.println("");
return printer;
}
/**
* Normalized attribute value string.
*
* @param element the element
* @param attributeName the attribute name
* @return the string
*/
public static String normalizedAttributeValue(Element element, String attributeName) {
String value = element.getAttribute(attributeName);
if (StringUtil.isEmpty(value)) {
value = null;
}
return value;
}
/**
* Get child comments comment [ ].
*
* @param parent the parent
* @return the comment [ ]
*/
public static Comment[] getChildComments(Node parent) {
NodeList children;
if (parent instanceof Document) {
children = parent.getChildNodes();
} else if (parent instanceof Element) {
children = parent.getChildNodes();
} else {
throw new UnsupportedOperationException("Not a supported type: " + parent.getClass());
}
ArrayBuilder builder = new ArrayBuilder<>(Comment.class);
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child instanceof Comment) {
builder.add((Comment) child);
}
}
return builder.toArray();
}
// XML operations --------------------------------------------------------------------------------------------------
/**
* Parse file if exists document.
*
* @param file the file
* @return the document
* @throws IOException the io exception
*/
public static Document parseFileIfExists(File file) throws IOException {
if (file == null || !file.exists()) {
return null;
}
return parse(file.getAbsolutePath(), true, null, null, null);
}
/**
* Parse document.
*
* @param uri the uri
* @return the document
* @throws IOException the io exception
*/
public static Document parse(String uri) throws IOException {
return parse(uri, true, null, null, null);
}
/**
* Parse document.
*
* @param uri the uri
* @param namespaceAware the namespace aware
* @param resolver the resolver
* @param schemaUri the schema uri
* @param classLoader the class loader
* @return the document
* @throws IOException the io exception
*/
public static Document parse(String uri, boolean namespaceAware, EntityResolver resolver, String schemaUri, ClassLoader classLoader)
throws IOException {
InputStream stream = null;
try {
stream = IOUtil.getInputStreamForURI(uri);
return parse(stream, namespaceAware, resolver, schemaUri, classLoader, DEFAULT_ERROR_HANDLER);
} catch (ConfigurationError e) {
throw new ConfigurationError("Error parsing " + uri, e);
} finally {
IOUtil.close(stream);
}
}
/**
* Parse string document.
*
* @param text the text
* @return the document
*/
public static Document parseString(String text) {
return parseString(text, null, null);
}
/**
* Parse string as element element.
*
* @param xml the xml
* @return the element
*/
public static Element parseStringAsElement(String xml) {
return XMLUtil.parseString(xml).getDocumentElement();
}
/**
* Parse string document.
*
* @param text the text
* @param resolver the resolver
* @param classLoader the class loader
* @return the document
*/
public static Document parseString(String text, EntityResolver resolver, ClassLoader classLoader) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(text);
}
try {
String encoding = getEncoding(text, SystemInfo.getFileEncoding());
return parse(new ByteArrayInputStream(text.getBytes(encoding)), true, resolver, null, classLoader, DEFAULT_ERROR_HANDLER);
} catch (IOException e) {
throw new RuntimeException("Unexpected error", e);
}
}
/**
* Gets encoding.
*
* @param text the text
* @param defaultEncoding the default encoding
* @return the encoding
*/
public static String getEncoding(String text, String defaultEncoding) {
if (text.startsWith(" 0 && ei < qm2i) {
int dq = text.indexOf('"', ei);
int sq = text.indexOf('\'', ei);
int q1 = (dq > 0 ? (sq > 0 ? dq : Math.min(sq, dq)) : sq);
dq = text.indexOf('"', q1 + 1);
sq = text.indexOf('\'', q1 + 1);
int q2 = (dq > 0 ? (sq > 0 ? dq : Math.min(sq, dq)) : sq);
if (q1 > 0 && q2 > 0) {
return text.substring(q1 + 1, q2);
}
}
}
return defaultEncoding;
}
/**
* Parse document.
*
* @param stream the stream
* @return the document
* @throws IOException the io exception
*/
public static Document parse(InputStream stream) throws IOException {
return parse(stream, null, null, DEFAULT_ERROR_HANDLER);
}
/**
* Parses a stream's output into an XML document.
*
* @param in the {@link InputStream} to read
* @param resolver an {@link EntityResolver} implementation or null, in the latter case, no validation is applied
* @param schemaUri the URI of the XML document
* @param errorHandler the error handler
* @return the resulting XML {@link Document}
* @throws IOException if stream access fails
*/
public static Document parse(InputStream in, EntityResolver resolver, String schemaUri, ErrorHandler errorHandler) throws IOException {
return parse(in, true, resolver, schemaUri, null, errorHandler);
}
/**
* Parse document.
*
* @param stream the stream
* @param namespaceAware the namespace aware
* @param resolver the resolver
* @param schemaUri the schema uri
* @param classLoader the class loader
* @param errorHandler the error handler
* @return the document
* @throws IOException the io exception
*/
public static Document parse(InputStream stream, boolean namespaceAware, EntityResolver resolver,
String schemaUri, ClassLoader classLoader, ErrorHandler errorHandler)
throws IOException {
try {
DocumentBuilderFactory factory = createDocumentBuilderFactory(classLoader);
factory.setNamespaceAware(namespaceAware);
if (schemaUri != null) {
activateXmlSchemaValidation(factory, schemaUri);
}
DocumentBuilder builder = factory.newDocumentBuilder();
if (resolver != null) {
builder.setEntityResolver(resolver);
}
if (errorHandler == null) {
errorHandler = new ErrorHandler("XMLUtil");
}
builder.setErrorHandler(createSaxErrorHandler(errorHandler));
return builder.parse(stream);
} catch (SAXParseException e) {
throw new ConfigurationError("Error in line " + e.getLineNumber() + " column " + e.getColumnNumber(), e);
} catch (ParserConfigurationException | SAXException e) {
throw new ConfigurationError(e);
}
}
/**
* Gets default document builder class name.
*
* @return the default document builder class name
*/
public static String getDefaultDocumentBuilderClassName() {
return defaultDocumentBuilderClassName;
}
/**
* Sets default document builder class name.
*
* @param defaultDocumentBuilderClassName the default document builder class name
*/
public static void setDefaultDocumentBuilderClassName(String defaultDocumentBuilderClassName) {
XMLUtil.defaultDocumentBuilderClassName = defaultDocumentBuilderClassName;
}
/**
* Create document builder factory document builder factory.
*
* @param classLoader the class loader
* @return the document builder factory
*/
public static DocumentBuilderFactory createDocumentBuilderFactory(ClassLoader classLoader) {
if (defaultDocumentBuilderClassName != null) {
if (classLoader == null) {
classLoader = Thread.currentThread().getContextClassLoader();
}
return DocumentBuilderFactory.newInstance(defaultDocumentBuilderClassName, classLoader);
} else {
return DocumentBuilderFactory.newInstance();
}
}
/**
* Namespace alias namespace alias.
*
* @param document the document
* @param namespaceUri the namespace uri
* @return the namespace alias
*/
public static NamespaceAlias namespaceAlias(Document document, String namespaceUri) {
Map attributes = XMLUtil.getAttributes(document.getDocumentElement());
for (Map.Entry entry : attributes.entrySet()) {
String namespaceName = entry.getValue();
if (namespaceUri.equals(namespaceName)) {
String def = entry.getKey();
String alias = (def.contains(":") ? StringUtil.lastToken(def, ':') : "");
return new NamespaceAlias(alias, namespaceName);
}
}
return new NamespaceAlias("", namespaceUri);
}
/**
* Gets namespaces.
*
* @param document the document
* @return the namespaces
*/
public static Map getNamespaces(Document document) {
Map namespaces = new HashMap<>();
Map attributes = XMLUtil.getAttributes(document.getDocumentElement());
for (Map.Entry entry : attributes.entrySet()) {
String attributeName = entry.getKey();
if (attributeName.startsWith("xmlns")) {
String alias = (attributeName.contains(":") ? StringUtil.lastToken(attributeName, ':') : "");
namespaces.put(alias, entry.getValue());
}
}
return namespaces;
}
/**
* Gets target namespace.
*
* @param xsdDocument the xsd document
* @return the target namespace
*/
public static String getTargetNamespace(Document xsdDocument) {
return xsdDocument.getDocumentElement().getAttribute("targetNamespace");
}
/**
* Gets boolean attribute.
*
* @param element the element
* @param attributeName the attribute name
* @param required the required
* @return the boolean attribute
*/
public static Boolean getBooleanAttribute(Element element, String attributeName, boolean required) {
String stringValue = element.getAttribute(attributeName);
if (StringUtil.isEmpty(stringValue) && required) {
throw new SyntaxError("Missing attribute '" + attributeName + "'", format(element));
}
return ParseUtil.parseBoolean(stringValue);
}
/**
* Gets boolean attribute with default.
*
* @param element the element
* @param attributeName the attribute name
* @param defaultValue the default value
* @return the boolean attribute with default
*/
public static boolean getBooleanAttributeWithDefault(Element element, String attributeName, boolean defaultValue) {
String stringValue = element.getAttribute(attributeName);
return (StringUtil.isEmpty(stringValue) ? defaultValue : Boolean.parseBoolean(stringValue));
}
/**
* Gets double attribute.
*
* @param element the element
* @param name the name
* @return the double attribute
*/
public static double getDoubleAttribute(Element element, String name) {
return Double.parseDouble(element.getAttribute(name));
}
/**
* Gets date attribute.
*
* @param element the element
* @param name the name
* @return the date attribute
*/
public static Date getDateAttribute(Element element, String name) {
return new String2DateConverter<>().convert(element.getAttribute(name));
}
/**
* Gets zone date time attribute.
*
* @param element the element
* @param attributeName the attribute name
* @param pattern the pattern
* @return the zone date time attribute
*/
public static ZonedDateTime getZoneDateTimeAttribute(Element element, String attributeName, String pattern) {
String text = getAttribute(element, attributeName, true);
return (text != null ? ZonedDateTime.parse(text, DateTimeFormatter.ofPattern(pattern)) : null);
}
/**
* Gets local date attribute.
*
* @param element the element
* @param attributeName the attribute name
* @param pattern the pattern
* @return the local date attribute
*/
public static LocalDate getLocalDateAttribute(Element element, String attributeName, String pattern) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
String text = getAttribute(element, attributeName, true);
return LocalDate.parse(text, formatter);
}
/**
* Map attributes to properties.
*
* @param element the element
* @param bean the bean
* @param unescape the unescape
*/
public static void mapAttributesToProperties(Element element, Object bean, boolean unescape) {
mapAttributesToProperties(element, bean, unescape, new NoOpConverter<>());
}
/**
* Map attributes to properties.
*
* @param element the element
* @param bean the bean
* @param unescape the unescape
* @param nameNormalizer the name normalizer
*/
public static void mapAttributesToProperties(Element element, Object bean, boolean unescape, Converter nameNormalizer) {
for (Map.Entry attribute : getAttributes(element).entrySet()) {
String name = StringUtil.lastToken(attribute.getKey(), ':');
name = nameNormalizer.convert(name);
String value = attribute.getValue();
if (unescape) {
value = StringUtil.unescape(value);
}
Class> type = bean.getClass();
if (BeanUtil.hasProperty(type, name)) {
BeanUtil.setPropertyValue(bean, name, value, true, true);
}
}
}
/**
* Visit.
*
* @param element the element
* @param visitor the visitor
*/
public static void visit(Node element, Visitor visitor) {
visitor.visit(element);
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
visit(childNodes.item(i), visitor);
}
}
/**
* Find element by attribute element.
*
* @param attributeName the attribute name
* @param attributeValue the attribute value
* @param root the root
* @return the element
*/
public static Element findElementByAttribute(String attributeName, String attributeValue, Element root) {
if (attributeValue.equals(root.getAttribute(attributeName))) {
return root;
} else {
for (Element child : XMLUtil.getChildElements(root)) {
Element candidate = findElementByAttribute(attributeName, attributeValue, child);
if (candidate != null) {
return candidate;
}
}
}
return null;
}
/**
* Find first accepted element.
*
* @param filter the filter
* @param element the element
* @return the element
*/
public static Element findFirstAccepted(Filter filter, Element element) {
if (filter.accept(element)) {
return element;
} else {
for (Element child : XMLUtil.getChildElements(element)) {
Element candidate = findFirstAccepted(filter, child);
if (candidate != null) {
return candidate;
}
}
}
return null;
}
/**
* Find elements by name list.
*
* @param name the name
* @param caseSensitive the case sensitive
* @param root the root
* @return the list
*/
public static List findElementsByName(String name, boolean caseSensitive, Element root) {
return findElementsByName(name, caseSensitive, root, new ArrayList<>());
}
/**
* Gets whole text.
*
* @param element the element
* @return the whole text
*/
public static String getWholeText(Element element) {
StringBuilder builder = new StringBuilder();
NodeList nodeList = element.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node instanceof Text) {
builder.append(((Text) node).getWholeText());
} else if (node instanceof Element) {
builder.append(getWholeText((Element) node));
}
}
return builder.toString();
}
/**
* Format text string.
*
* @param text the text
* @return the string
*/
public static String formatText(String text) {
return text.replace("&", "&").replace("<", "<").replace(">", ">");
}
// private helpers -------------------------------------------------------------------------------------------------
private static void format(Element element, SimpleXMLWriter out) {
String name = element.getNodeName();
Map attributes = XMLUtil.getAttributes(element);
try {
out.startElement(name, attributes);
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
if (child instanceof Element) {
format((Element) child, out);
} else if (child instanceof Text) {
String text = child.getTextContent();
if (!StringUtil.isEmpty(text)) {
out.characters(text.toCharArray(), 0, text.length());
}
}
}
out.endElement(name);
} catch (SAXException e) {
throw new RuntimeException(e);
}
}
private static List findElementsByName(String name, boolean caseSensitive, Element root, List result) {
if (root.getNodeName().equals(name)) {
result.add(root);
} else {
for (Element child : getChildElements(root)) {
findElementsByName(name, caseSensitive, child, result);
}
}
return result;
}
private static void activateXmlSchemaValidation(DocumentBuilderFactory factory, String schemaUrl) {
try {
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(new URL(schemaUrl));
factory.setSchema(schema);
} catch (Exception e) {
// some XML parsers may not support attributes in general or especially XML Schema
LOGGER.error("Error activating schema validation for schema " + schemaUrl + ", possibly you are offline or behind a proxy?", e.getMessage());
}
}
private static org.xml.sax.ErrorHandler createSaxErrorHandler(
final ErrorHandler errorHandler) {
return new org.xml.sax.ErrorHandler() {
@Override
public void error(SAXParseException e) {
errorHandler.handleError(e.getMessage(), e);
}
@Override
public void fatalError(SAXParseException e) {
errorHandler.handleError(e.getMessage(), e);
}
@Override
public void warning(SAXParseException e) {
errorHandler.handleError(e.getMessage(), e);
}
};
}
/**
* Save as properties.
*
* @param properties the properties
* @param file the file
* @param encoding the encoding
* @throws FileNotFoundException the file not found exception
*/
@SuppressWarnings("null")
public static void saveAsProperties(Properties properties, File file, String encoding) throws FileNotFoundException {
if (properties.size() == 0) {
throw new IllegalArgumentException("Cannot save empty Properties");
}
Document document = null;
for (Map.Entry