All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.terapico.utils.LightXmlData Maven / Gradle / Ivy

package com.terapico.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.stream.Collectors;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 
 * 一个构造XML数据,并生成字符串的例子
 * 一个解析字符串为XML对象的例子。
 *
 * 
 * @author clariones
 *
 */
public class LightXmlData {
	public static class Builder {
		protected Stack stack;
		protected LightXmlData rootNode;
		protected boolean forMetaData = false;
		protected boolean waitChild = false;

		public Builder() {
			this("xml");
		}

		public Builder(String tagName) {
			stack = new Stack<>();
			rootNode = new LightXmlData();
			rootNode.setTagName(tagName);
			waitChild = true;
			stack.push(rootNode);
		}

		public Builder meta() throws Exception {
			if (stack.peek() != rootNode) {
				throw new Exception("meta()必须在根节点声明");
			}
			rootNode.setMeta(new XmlMetaData());
			forMetaData = true;
			return this;
		}

		public Builder version(String val) throws Exception {
			verifyInMetaScope("version");
			rootNode.getMeta().setVersion(val);
			return this;
		}

		private void verifyInMetaScope(String methodName) throws Exception {
			if (!forMetaData) {
				throw new Exception("方法" + methodName + "()只能在meta内使用。");
			}
		}

		private void verifyNotInMetaScope(String methodName) throws Exception {
			if (forMetaData) {
				throw new Exception("方法" + methodName + "()不能在meta内使用。");
			}
		}

		public Builder node(String tagName, Object value) {
			forMetaData = false;
			LightXmlData childNode = new LightXmlData();
			childNode.setTagName(tagName);
			childNode.setValue(value);

			if (waitChild) {
				// 添加子节点
				LightXmlData curNode = stack.peek();
				curNode.addChild(childNode);
				stack.push(childNode);
				waitChild = false;
			} else {
				// 添加兄弟节点
				stack.pop();
				LightXmlData parentNode = stack.peek();
				stack.push(childNode);
				parentNode.addChild(childNode);
			}
			return this;
		}

		public Builder cdata() throws Exception {
			verifyNotInMetaScope("cdata");
			LightXmlData curNode = stack.peek();
			curNode.setWrapperCdata(true);
			return this;
		}

		public Builder attribute(String name, Object value) throws Exception {
			verifyNotInMetaScope("attribute");
			LightXmlData curNode = stack.peek();
			curNode.addAttribute(name, value);
			return this;
		}

		public Builder child() {
			waitChild = true;
			return this;
		}

		public Builder done() {
			waitChild = false;
			stack.pop();
			return this;
		}

		public LightXmlData build() {
			return rootNode;
		}

		private LightXmlData getCurrentNode() {
			return stack.peek();
		}

		public LightXmlData fromXmlString(String xmlStr) throws Exception {
			if (xmlStr == null || xmlStr.isEmpty()) {
				return new LightXmlData();
			}
			stack.clear();
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8)));
			NodeList msgParamNodes = doc.getDocumentElement().getChildNodes();
			decode(doc.getDocumentElement());
			return this.build();
		}

		private void decode(Node node) throws Exception {
			boolean addChild = false;
			// System.out.println("Now read node " +
			// node.getNodeName()+"("+node.getNodeType()+"), value="+node.getNodeValue());
			short nodeType = node.getNodeType();
			switch (nodeType) {
			case Node.ENTITY_REFERENCE_NODE:
			case Node.DOCUMENT_FRAGMENT_NODE:
			case Node.DOCUMENT_TYPE_NODE:
			case Node.NOTATION_NODE:
			case Node.PROCESSING_INSTRUCTION_NODE:
				return;
			// 忽略以上类型的node
			case Node.ATTRIBUTE_NODE:
				this.attribute(node.getNodeName(), node.getNodeValue());
				return;
			case Node.TEXT_NODE:
			case Node.CDATA_SECTION_NODE:
				if (TextUtil.isBlank(node.getTextContent())) {
					return;
				}
				getCurrentNode().setValue(node.getTextContent());
				return;
			case Node.ENTITY_NODE:
			case Node.DOCUMENT_NODE:
			case Node.ELEMENT_NODE:
				if (stack.isEmpty()) {
					rootNode.setTagName(node.getNodeName());
					stack.push(rootNode);
				} else {
					this.node(node.getNodeName(), null);
				}
			default:
				break;
			}

			NamedNodeMap attrs = node.getAttributes();
			if (attrs != null) {
				for (int i = 0; i < attrs.getLength(); i++) {
					Node attrNode = attrs.item(i);
					this.attribute(attrNode.getNodeName(), attrNode.getNodeValue());
				}
			}
			NodeList children = node.getChildNodes();
			if (children == null) {
				return;
			}
			addChild = false;
			for (int i = 0; i < children.getLength(); i++) {
				Node childNode = children.item(i);
				if (!addChild) {
					switch (childNode.getNodeType()) {
					case Node.ENTITY_NODE:
					case Node.DOCUMENT_NODE:
					case Node.ELEMENT_NODE:
						this.child();
						addChild = true;
						// System.out.println("ready to add child");
						break;
					}
				}
				decode(childNode);
			}
			if (addChild) {
				// System.out.println("finish add child");
				this.done();
			}
			return;
		}

	}

	public static class XmlMetaData {
		protected String version;

		public String getVersion() {
			return version;
		}

		public void setVersion(String version) {
			this.version = version;
		}
	}

	public static class NodeWrapper {
		List node;

		public boolean isPresent() {
			return node != null && node.size() > 0;
		}

		public NodeWrapper get(int index) {
			if (node == null) {
				return this;
			}
			if (node.size() <= index) {
				return this;
			}
			NodeWrapper rst = new NodeWrapper();
			rst.node = new ArrayList<>();
			rst.node.add(node.get(index));
			return rst;
		}

		public LightXmlData get() {
			if (node == null) {
				return null;
			}
			if (node.size() > 0) {
				return node.get(0);
			}
			return null;
		}

		public List getAll() {
			return node;
		}

		public NodeWrapper child(String name) {
			LightXmlData firstNode = get();
			if (firstNode == null) {
				return new NodeWrapper();
			}
			return firstNode.child(name);
		}
	}

	protected XmlMetaData meta;
	protected List children;
	protected String tagName;
	protected Object value;
	protected LinkedHashMap attributes;
	protected boolean wrapperCdata = false;

	public XmlMetaData getMeta() {
		return meta;
	}

	public void addAttribute(String name, Object value) {
		ensureAttributes();
		attributes.put(name, value);
	}

	private void ensureAttributes() {
		if (attributes == null) {
			attributes = new LinkedHashMap<>();
		}
	}

	protected void addChild(LightXmlData childNode) {
		ensureChildren();
		children.add(childNode);
	}

	private void ensureChildren() {
		if (children == null) {
			children = new ArrayList<>();
		}
	}

	public void setMeta(XmlMetaData meta) {
		this.meta = meta;
	}

	public List getChildren() {
		return children;
	}

	public void setChildren(List children) {
		this.children = children;
	}

	public String getTagName() {
		return tagName;
	}

	public void setTagName(String tagName) {
		this.tagName = tagName;
	}

	public Object getValue() {
		return value;
	}

	public void setValue(Object value) {
		this.value = value;
	}

	public LinkedHashMap getAttributes() {
		return attributes;
	}

	public void setAttributes(LinkedHashMap attributes) {
		this.attributes = attributes;
	}

	public boolean isWrapperCdata() {
		return wrapperCdata;
	}

	public void setWrapperCdata(boolean wrapperCdata) {
		this.wrapperCdata = wrapperCdata;
	}

	public String toXML() throws UnsupportedEncodingException {
		return toXML(false);
	}

	public String toXML(boolean pretty) throws UnsupportedEncodingException {
		return toXML(pretty, false);
	}
	public String toXML(boolean pretty, boolean newLineForAttribute) throws UnsupportedEncodingException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		PrintStream pOut = new PrintStream(out);
		if (this.getMeta() != null) {
			printMetaData(pOut);
		}
		printNodeData(pOut, this, 0, pretty, newLineForAttribute);
		pOut.close();
		return out.toString("utf-8");
	}

	private void printNodeData(PrintStream out, LightXmlData node, int level, boolean pretty, boolean newLineForAttribute) {
		if (pretty) {
			for (int i = 0; i < level; i++) {
				out.print("  ");
			}
		}
		if (node.getAttributes() == null) {
			out.printf("<%s>", node.getTagName());
		} else {
			out.printf("<%s", node.getTagName());
			node.getAttributes().forEach((key, value) -> {
				if (newLineForAttribute) {
					out.println();
					if (pretty) {
						for (int i = 0; i < level+2; i++) {
							out.print("  ");
						}
					}
				}
				out.printf(" %s=\"%s\"", key, convertNodeValueToString(value));
			});
			out.print(">");
		}
		printNodeValue(out, node);
		if (node.getChildren() == null) {
			out.println(String.format("", node.getTagName()));
			return;
		}
		out.println();
		for (LightXmlData child : node.getChildren()) {
			printNodeData(out, child, level + 1, pretty, newLineForAttribute);
		}
		if (pretty) {
			out.println();
			for (int i = 0; i < level; i++) {
				out.print("  ");
			}
		}
		out.println(String.format("", node.getTagName()));
	}

	private void printNodeValue(PrintStream out, LightXmlData node) {
		if (node.getValue() == null) {
			return;
		}
		if (node.isWrapperCdata()) {
			out.printf("", convertNodeValueToString(node.getValue()));
		} else {
			out.print(convertNodeValueToString(node.getValue()));
		}
	}

	private String convertNodeValueToString(Object value) {
		return value.toString();
	}

	private void printMetaData(PrintStream out) {
		out.print("");
	}

	public NodeWrapper child(String name) {
		return children(name);
	}

	public NodeWrapper children(String name) {
		if (children == null) {
			return new NodeWrapper();
		}
		List nodes = children.stream().filter(it -> it.getTagName().equals(name))
				.collect(Collectors.toList());
		if (nodes.isEmpty()) {
			return new NodeWrapper();
		}
		NodeWrapper rst = new NodeWrapper();
		rst.node = nodes;
		return rst;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy