host.anzo.commons.io.xml.XmlParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-core Show documentation
Show all versions of commons-core Show documentation
Commons library to make me happy.
package host.anzo.commons.io.xml;
import host.anzo.commons.utils.ZipUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author ANZO
*/
public class XmlParser implements AutoCloseable {
private final Path filePath;
private final String name;
private final String content;
private final Map nameAttributes = new HashMap<>();
private final Map> nameChildren = new HashMap<>();
@SuppressWarnings("unused")
private InputStream inputStream;
private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
static {
documentBuilderFactory.setIgnoringComments(true);
documentBuilderFactory.setIgnoringElementContentWhitespace(true);
}
/**
* @param fileName file name
* @return XmlParser loaded from specified file
*/
public static @NotNull XmlParser fromFile(@NotNull String fileName) {
try (FileInputStream stream = new FileInputStream(fileName)) {
return new XmlParser(Paths.get(fileName), Objects.requireNonNull(rootElement(stream)));
}
catch (IOException e) {
throw new RuntimeException("Can't parse XML file:" + fileName, e);
}
}
/**
* @param path the file path
* @return XmlParser loaded from the specified file path
*/
public static @NotNull XmlParser fromPath(@NotNull Path path) {
try (FileInputStream stream = new FileInputStream(path.toFile())) {
return new XmlParser(path, Objects.requireNonNull(rootElement(stream)));
}
catch (IOException e) {
throw new RuntimeException("Can't parse XML file:" + path, e);
}
}
/**
* @param fileNames zip file names
* @return list of XmlParsers loaded from specified zip files
*/
public static @NotNull List fromZip(String @NotNull ... fileNames) {
final List results = new ArrayList<>();
for (String fileName : fileNames) {
try(FileSystem zipFileSystem = ZipUtils.createZipFileSystem(fileName, false)) {
if (zipFileSystem != null) {
try(final Stream filePathsInZip = Files.walk(zipFileSystem.getPath("/"))) {
filePathsInZip.forEach(filePathInZip -> {
if (filePathInZip.toString().endsWith(".xml")) {
try (InputStream stream = Files.newInputStream(filePathInZip)) {
results.add(XmlParser.fromInputStream(filePathInZip, stream));
}
catch (IOException e) {
throw new RuntimeException("Can't parse XML file name=" + filePathInZip + " from zip archive name=" + fileName, e);
}
}
});
}
}
}
catch (IOException e) {
throw new RuntimeException("Can't load XML files from zip archive name=" + fileName, e);
}
}
return results;
}
/**
* @param fileName resource file name
* @param classLoader class loader
* @return XmlParser loaded from specified resource
* @throws IOException when resource can't be read
*/
public static @NotNull XmlParser fromResource(String fileName, @NotNull ClassLoader classLoader) throws IOException {
return fromInputStream(Paths.get(fileName), classLoader.getResourceAsStream(fileName));
}
/**
* @param filePath file path
* @param inputStream input stream to read
* @return XmlParser loaded from specified input stream
* @throws IOException when input stream can't be read
*/
public static @NotNull XmlParser fromInputStream(Path filePath, InputStream inputStream) throws IOException {
return new XmlParser(filePath, Objects.requireNonNull(rootElement(inputStream)));
}
private XmlParser(Path filePath, @NotNull Element element) {
this.filePath = filePath;
this.name = element.getNodeName();
this.content = element.getTextContent();
final NamedNodeMap namedNodeMap = element.getAttributes();
int nodeCount = namedNodeMap.getLength();
for (int i = 0; i < nodeCount; i++) {
final Node node = namedNodeMap.item(i);
final String name = node.getNodeName();
this.nameAttributes.put(name.toLowerCase(), node.getNodeValue());
}
final NodeList nodes = element.getChildNodes();
nodeCount = nodes.getLength();
for (int i = 0; i < nodeCount; i++) {
final Node node = nodes.item(i);
final int type = node.getNodeType();
if (type == Node.ELEMENT_NODE) {
final XmlParser child = new XmlParser(filePath, (Element) node);
this.nameChildren.computeIfAbsent(node.getNodeName().toLowerCase(), k -> new ArrayList<>()).add(child);
}
}
}
public String getFileName() {
if (filePath == null) {
return "";
}
return filePath.getFileName().toString();
}
public String getDirectoryName() {
if (filePath == null) {
return "";
}
return filePath.getParent().getFileName().toString();
}
public String name() {
return name;
}
public String content() {
return content;
}
public XmlParser child(String name) {
final XmlParser child = optChild(name);
if (child == null) {
throw new RuntimeException("Could not find child node: " + name);
}
return child;
}
public XmlParser optChild(String name) {
final List children = children(name);
int n = children.size();
if (n > 1) {
throw new RuntimeException("Could not find individual child node: " + name);
}
return n == 0 ? null : children.stream().findFirst().orElse(null);
}
public List children() {
return nameChildren.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
}
public List children(@NotNull String name) {
final List children = nameChildren.get(name.toLowerCase());
return children == null ? new ArrayList<>() : children;
}
public Set attributeNames() {
return nameAttributes.keySet();
}
public boolean hasAttribute(@NotNull String attributeName) {
return nameAttributes.containsKey(attributeName.toLowerCase());
}
public String readString(@NotNull String name, String defaultValue) {
final String value = nameAttributes.get(name.toLowerCase());
return value != null ? value : defaultValue;
}
public String readString(String name) {
return readString(name, null);
}
public int readInt(String name, int defaultValue) {
final String result = Optional.ofNullable(readString(name)).orElse("").replace("_","");
if (NumberUtils.isCreatable(result)) {
return Integer.parseInt(result);
}
return defaultValue;
}
public int readInt(String name) {
return Integer.parseInt(Optional.ofNullable(readString(name)).orElse("").replace("_",""));
}
public int readIntHex(String name) {
return Integer.decode(readString(name));
}
public long readLong(String name, long defaultValue) {
final String result = Optional.ofNullable(readString(name)).orElse("").replace("_","");
if (NumberUtils.isCreatable(result)) {
return Long.parseUnsignedLong(result);
}
return defaultValue;
}
public long readLong(String name) {
return Long.parseLong(Optional.ofNullable(readString(name)).orElse("").replace("_",""));
}
public float readFloat(String name, float defaultValue) {
final String result = Optional.ofNullable(readString(name)).orElse("").replace("_","");
if (!StringUtils.isEmpty(result)) {
return Float.parseFloat(result);
}
return defaultValue;
}
public float readFloat(String name) {
return Float.parseFloat(Optional.ofNullable(readString(name)).orElse("").replace("_",""));
}
public boolean readBoolean(String name, boolean defaultValue) {
final String result = readString(name);
if (result != null) {
return Boolean.parseBoolean(result.toLowerCase());
}
return defaultValue;
}
public boolean readBoolean(String name) {
return Boolean.parseBoolean(readString(name).toLowerCase());
}
public final > T readEnum(String name, Class enumClass, T defaultValue) {
final String value = readString(name);
if (value == null || StringUtils.isEmpty(value.trim())) {
return defaultValue;
}
try {
if (StringUtils.isNumeric(value)) {
return enumClass.getEnumConstants()[Integer.parseInt(value)];
}
else {
return Enum.valueOf(enumClass, value);
}
}
catch (Exception e) {
throw new IllegalArgumentException("Enum value of type " + enumClass.getName() + " required, but found: " + value, e);
}
}
public List readStringList(String name, String splitter) {
final String value = readString(name);
if (StringUtils.isEmpty(value)) {
return Collections.emptyList();
}
return Arrays.stream(value.split(splitter)).map(String::trim).collect(Collectors.toList());
}
private static @Nullable Element rootElement(InputStream inputStream) throws IOException {
try {
final DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
if (builder != null) {
return builder.parse(inputStream).getDocumentElement();
}
return null;
}
catch (IOException | SAXException | ParserConfigurationException exception) {
throw new RuntimeException("Can't parse XML document", exception);
}
finally {
inputStream.close();
}
}
@Override
public void close() throws Exception {
if (inputStream != null) {
inputStream.close();
}
}
}