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

com.jianggujin.http.util.JXMLUtils Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2018 jianggujin (www.jianggujin.com).
 * 
 * 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.jianggujin.http.util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 * XML工具,禁用实体解析
 * 
 * @author jianggujin
 *
 */
public class JXMLUtils {
    public final static String FRATURE_DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
    public final static String FRATURE_EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
    public final static String FRATURE_EXTERNAL_PARAMETER_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
    public final static String FRATURE_LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
    public final static String SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";

    public static DocumentBuilderFactory newDocumentBuilderFactory() throws ParserConfigurationException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setFeature(FRATURE_DISALLOW_DOCTYPE_DECL, true);
        documentBuilderFactory.setFeature(FRATURE_EXTERNAL_GENERAL_ENTITIES, false);
        documentBuilderFactory.setFeature(FRATURE_EXTERNAL_PARAMETER_ENTITIES, false);
        documentBuilderFactory.setFeature(FRATURE_LOAD_EXTERNAL_DTD, false);
        // documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
        // true);
        documentBuilderFactory.setXIncludeAware(false);
        documentBuilderFactory.setExpandEntityReferences(false);
        return documentBuilderFactory;
    }

    public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
        return newDocumentBuilderFactory().newDocumentBuilder();
    }

    public static Document newDocument() throws ParserConfigurationException {
        return newDocumentBuilder().newDocument();
    }

    public static SAXParserFactory newSAXParserFactory() throws ParserConfigurationException, SAXException {
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        saxParserFactory.setFeature(FRATURE_EXTERNAL_GENERAL_ENTITIES, false);
        saxParserFactory.setFeature(FRATURE_EXTERNAL_PARAMETER_ENTITIES, false);
        saxParserFactory.setFeature(FRATURE_LOAD_EXTERNAL_DTD, false);
        return saxParserFactory;
    }

    /**
     * SAX
     * 
     * @return
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    public static SAXParser newSAXParser() throws ParserConfigurationException, SAXException {
        return newSAXParserFactory().newSAXParser();
    }

    /**
     * SAX2
     * 
     * @return
     * @throws SAXException
     */
    public static XMLReader newXMLReader() throws SAXException {
        XMLReader reader = XMLReaderFactory.createXMLReader();
        reader.setFeature(FRATURE_DISALLOW_DOCTYPE_DECL, true);
        // This may not be strictly required as DTDs shouldn't be allowed at all,
        // per previous line.
        reader.setFeature(FRATURE_LOAD_EXTERNAL_DTD, false);
        reader.setFeature(FRATURE_EXTERNAL_GENERAL_ENTITIES, false);
        reader.setFeature(FRATURE_EXTERNAL_PARAMETER_ENTITIES, false);
        return reader;
    }

    public static TransformerFactory newTransformerFactory() {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
        transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
        return transformerFactory;
    }

    public static XMLInputFactory newXMLInputFactory() {
        XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
        // This disables DTDs entirely for that factory
        xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
        // disable external entities
        xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
        return xmlInputFactory;
    }

    public static Validator newValidator() throws SAXException {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE);
        Schema schema = schemaFactory.newSchema();
        Validator validator = schema.newValidator();
        validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
        validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
        return validator;
    }

    public static SchemaFactory newSchemaFactory() throws SAXException {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE);
        schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
        schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
        return schemaFactory;
    }

    public static SAXTransformerFactory newSAXTransformerFactory() throws SAXException {
        SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
        sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
        sf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
        return sf;
    }

    public static  T unmarshal(Class classesToBeBound, InputSource source)
            throws ParserConfigurationException, SAXException, JAXBException {
        SAXParserFactory saxParserFactory = newSAXParserFactory();
        Source xmlSource = new SAXSource(saxParserFactory.newSAXParser().getXMLReader(), source);
        return unmarshal(classesToBeBound, xmlSource);
    }

    @SuppressWarnings("unchecked")
    public static  T unmarshal(Class classesToBeBound, Source source) throws JAXBException {
        JAXBContext jc = JAXBContext.newInstance(classesToBeBound);
        Unmarshaller um = jc.createUnmarshaller();
        return (T) um.unmarshal(source);
    }

    /**
     * 创建XML文档
     * 
     * @param transformerFactory
     * @param map
     * @param root
     * @param streamResult
     * @param properties
     * @throws ParserConfigurationException
     * @throws TransformerException
     * @throws SAXException
     * @see OutputKeys
     */
    public static void create(TransformerFactory transformerFactory, Map map, String root,
            StreamResult streamResult, String... properties)
            throws ParserConfigurationException, TransformerException, SAXException {
        if (transformerFactory instanceof SAXTransformerFactory) {
            SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) transformerFactory;
            TransformerHandler transformerHandler = saxTransformerFactory.newTransformerHandler();
            Transformer transformer = transformerHandler.getTransformer();
            setOutputProperty(transformer, properties);
            transformerHandler.setResult(streamResult);
            transformerHandler.startDocument();
            transformerHandler.startElement(null, null, root, null);
            for (Entry entry : map.entrySet()) {
                String key = entry.getKey(), value = entry.getValue();
                transformerHandler.startElement(null, null, key, null);
                if (!JDataUtils.isEmpty(value)) {
                    char[] characters = value.toCharArray();
                    transformerHandler.characters(characters, 0, characters.length);
                }
                transformerHandler.endElement(null, null, key);
            }
            transformerHandler.endElement(null, null, root);
            transformerHandler.endDocument();
        } else {
            Document document = newDocument();
            document.setXmlStandalone(true);
            Element rootNode = document.createElement(root);
            for (Entry entry : map.entrySet()) {
                String key = entry.getKey(), value = entry.getValue();
                Element node = document.createElement(key);
                if (!JDataUtils.isEmpty(value)) {
                    node.setTextContent(value);
                }
                rootNode.appendChild(node);
            }
            document.appendChild(rootNode);
            Transformer transformer = transformerFactory.newTransformer();
            Source source = new DOMSource(document);
            setOutputProperty(transformer, properties);
            transformer.transform(source, streamResult);
        }
    }

    /**
     * 创建XML文档
     * 
     * @param transformerFactory
     * @param element
     * @param streamResult
     * @param properties
     * @throws ParserConfigurationException
     * @throws TransformerException
     * @throws SAXException
     * @see OutputKeys
     */
    public static void create(TransformerFactory transformerFactory, JElement element, StreamResult streamResult,
            String... properties) throws ParserConfigurationException, TransformerException, SAXException {
        if (transformerFactory instanceof SAXTransformerFactory) {
            SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) transformerFactory;
            TransformerHandler transformerHandler = saxTransformerFactory.newTransformerHandler();
            Transformer transformer = transformerHandler.getTransformer();
            setOutputProperty(transformer, properties);
            transformerHandler.setResult(streamResult);
            transformerHandler.startDocument();
            create(element, transformerHandler);
            transformerHandler.endDocument();
        } else {
            Document document = newDocument();
            document.setXmlStandalone(true);
            document.appendChild(create(element, document));
            Transformer transformer = transformerFactory.newTransformer();
            Source source = new DOMSource(document);
            setOutputProperty(transformer, properties);
            transformer.transform(source, streamResult);
        }
    }

    private static void setOutputProperty(Transformer transformer, String... properties) {
        int len = properties.length;
        if (len > 0 && len % 2 == 0) {
            for (int i = 0; i < len; i++) {
                transformer.setOutputProperty(properties[i], properties[++i]);
            }
        }
    }

    private static void create(JElement element, TransformerHandler transformerHandler) throws SAXException {
        AttributesImpl atts = new AttributesImpl();
        Collection attributes = element.getAttributes();
        if (attributes != null) {
            for (JAttribute attribute : attributes) {
                atts.addAttribute(attribute.getUri(), attribute.getLocalName(), attribute.getQName(),
                        attribute.getType(), attribute.getValue());
            }
        }
        transformerHandler.startElement(element.getUri(), element.getLocalName(), element.getQName(), atts);

        List childrens = element.getChildrens();
        if (childrens != null) {
            for (JElement children : childrens) {
                create(children, transformerHandler);
            }
        }
        String text = element.getText();
        if (!JDataUtils.isEmpty(text)) {
            char[] characters = text.toCharArray();
            transformerHandler.characters(characters, 0, characters.length);
        }
        transformerHandler.endElement(element.getUri(), element.getLocalName(), element.getQName());
    }

    private static Element create(JElement element, Document document) throws ParserConfigurationException {
        Element node = document.createElement(element.qName);
        if (!JDataUtils.isEmpty(element.text)) {
            node.setTextContent(element.text);
        }
        Collection attributes = element.getAttributes();
        if (attributes != null) {
            for (JAttribute attribute : attributes) {
                node.setAttribute(attribute.getQName(), attribute.getValue());
            }
        }
        List childrens = element.getChildrens();
        if (childrens != null) {
            for (JElement children : childrens) {
                node.appendChild(create(children, document));
            }
        }
        return node;
    }

    /**
     * 解析
     * 
     * @param source
     * @param xmlHandler
     * @return
     * @throws IOException
     * @throws SAXException
     */
    public static  T parse(InputSource source, JXmlHandler xmlHandler) throws IOException, SAXException {
        return parse(newXMLReader(), source, xmlHandler);
    }

    /**
     * 解析
     * 
     * @param reader
     * @param source
     * @param xmlHandler
     * @return
     * @throws IOException
     * @throws SAXException
     */
    public static  T parse(XMLReader reader, InputSource source, JXmlHandler xmlHandler)
            throws IOException, SAXException {
        reader.setContentHandler(xmlHandler);
        reader.setEntityResolver(xmlHandler);
        reader.setErrorHandler(xmlHandler);
        reader.setDTDHandler(xmlHandler);
        reader.parse(source);
        return xmlHandler.getData();
    }

    /**
     * 将Element子元素解析成Map
     * 
     * @param element
     * @return
     * @throws IOException
     * @throws SAXException
     */
    public static Map parse(Element element) throws IOException, SAXException {
        NodeList nodeList = element.getChildNodes();
        Map map = new HashMap();
        int len;
        if (nodeList != null && (len = nodeList.getLength()) > 0) {
            for (int i = 0; i < len; i++) {
                Node node = nodeList.item(i);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    Element child = (Element) node;
                    map.put(child.getNodeName(), child.getTextContent());
                }
            }
        }
        return map;
    }

    public static class JElement {
        private String uri;
        private String localName;
        private String qName;
        private Map attributes;
        private String text;
        private JElement parent;
        private List childrens;

        public JElement() {
        }

        public JElement(String qName) {
            this.qName = qName;
        }

        public JElement(String qName, String text) {
            this.qName = qName;
            this.text = text;
        }

        public String getUri() {
            return uri;
        }

        public JElement setUri(String uri) {
            this.uri = uri;
            return this;
        }

        public String getLocalName() {
            return localName;
        }

        public JElement setLocalName(String localName) {
            this.localName = localName;
            return this;
        }

        public String getQName() {
            return qName;
        }

        public JElement setQName(String qName) {
            this.qName = qName;
            return this;
        }

        public Collection getAttributes() {
            return attributes == null ? null : attributes.values();
        }

        public JElement setAttributes(String qName, String value) {
            return setAttributes(new JAttribute(qName, value));
        }

        public JElement setAttributes(JAttribute attribute) {
            if (attributes == null) {
                synchronized (this) {
                    if (attributes == null) {
                        attributes = new LinkedHashMap();
                    }
                }
            }
            this.attributes.put(attribute.getQName(), attribute);
            return this;
        }

        public String getText() {
            return text;
        }

        public JElement setText(String text) {
            this.text = text;
            return this;
        }

        public JElement getParent() {
            return parent;
        }

        private JElement setParent(JElement parent) {
            this.parent = parent;
            return this;
        }

        public List getChildrens() {
            return childrens;
        }

        public JElement appendChildren(String qName, String text) {
            return appendChildren(new JElement(qName, text));
        }

        public JElement appendChildren(JElement children) {
            if (childrens == null) {
                synchronized (this) {
                    if (childrens == null) {
                        childrens = new ArrayList();
                    }
                }
            }
            children.setParent(this);
            this.childrens.add(children);
            return this;
        }

        @Override
        public String toString() {
            return "[uri=" + uri + ", localName=" + localName + ", qName=" + qName + ", attributes=" + attributes
                    + ", text=" + text + ", childrens=" + childrens + "]";
        }
    }

    public static class JAttribute {

        private String uri;;
        public String localName;
        public String qName;
        public String type;
        public String value;

        public JAttribute() {
        }

        public JAttribute(String qName) {
            this.qName = qName;
        }

        public JAttribute(String qName, String value) {
            this.qName = qName;
            this.value = value;
        }

        public String getUri() {
            return uri;
        }

        public JAttribute setUri(String uri) {
            this.uri = uri;
            return this;
        }

        public String getLocalName() {
            return localName;
        }

        public JAttribute setLocalName(String localName) {
            this.localName = localName;
            return this;
        }

        public String getQName() {
            return qName;
        }

        public JAttribute setQName(String qName) {
            this.qName = qName;
            return this;
        }

        public String getType() {
            return type;
        }

        public JAttribute setType(String type) {
            this.type = type;
            return this;
        }

        public String getValue() {
            return value;
        }

        public JAttribute setValue(String value) {
            this.value = value;
            return this;
        }

        @Override
        public String toString() {
            return "[url=" + uri + ", localName=" + localName + ", qName=" + qName + ", value=" + value + "]";
        }

    }

    public static interface JXmlHandler extends ContentHandler, EntityResolver, ErrorHandler, DTDHandler {
        T getData();
    }

    public static class JElementXmlHandler extends DefaultHandler implements JXmlHandler {
        private JElement root;
        private LinkedList stack = new LinkedList();

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            int len = attributes.getLength();
            JElement element = new JElement();
            if (root == null) {
                root = element;
            }
            element.uri = uri;
            element.localName = localName;
            element.qName = qName;
            if (len > 0) {
                for (int i = 0; i < len; i++) {
                    JAttribute attribute = new JAttribute();
                    attribute.uri = attributes.getURI(i);
                    attribute.localName = attributes.getLocalName(i);
                    attribute.qName = attributes.getQName(i);
                    attribute.type = attributes.getType(i);
                    attribute.value = attributes.getValue(i);
                    element.setAttributes(attribute);
                }
            }
            JElement parent = stack.peek();
            if (parent != null) {
                parent.appendChildren(element);
            }
            stack.push(element);
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            stack.peek().text = new String(ch, start, length);
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            JElement element = stack.peek();
            if (JDataUtils.equals(uri, element.uri) && JDataUtils.equals(localName, element.localName)
                    && JDataUtils.equals(qName, element.qName)) {
                stack.pop();
            }
        }

        @Override
        public JElement getData() {
            return this.root;
        }
    }

    public static class JMapXmlHandler extends DefaultHandler implements JXmlHandler> {
        private Map xmlMap = new HashMap();
        private String key;
        private int deep = 0;

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            if (++deep == 2) {
                key = qName;
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            if (key != null)
                xmlMap.put(key, new String(ch, start, length));
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            deep--;
            key = null;
        }

        @Override
        public Map getData() {
            return this.xmlMap;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy