org.easyxml.xml.Document.java Source code

Java tutorial

Introduction

Here is the source code for org.easyxml.xml.Document.java

Source

/*
 * Created on May 15, 2015
 *
 * 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 org.easyxml.xml;

import java.nio.charset.Charset;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.xml.sax.SAXException;

/**
 * 
 * Utility to support XML Document based on Element class.
 * 
 * @author William JIANG
 * 
 *         15 May 2015
 * 
 * 
 * 
 * @version $Id$
 */

public class Document extends Element {

    // Constants for XML Declaration composing

    public static final Charset DefaultCharset = Charset.forName("UTF-8");

    private static final String DefaultDeclarationFormat = "<?xml version=\"1.0\" encoding=\"%s\"?>\n";

    // Usually we have only one element for all valid children element, then it
    // could be specified as this to facilitate most operations.

    protected Element defaultContainer = null;

    public Element getDefaultContainer() {

        return defaultContainer;

    }

    public Document(String name) {

        super(name);

    }

    /**
     * 
     * Set the DefaultContainer
     * 
     * @param container
     *            - The Element to be regarded as DefaultContainer.
     */

    protected void setDefaultContainer(Element container) {

        try {

            if (container == null) {

                throw new InvalidParameterException("The container is not valid!");

            }

            // Iterate through the DOM tree to make sure the container is a
            // descendant of this XmlDocument

            if (container != this) {

                Element parent = container;

                do {

                    parent = parent.getParent();

                    if (parent == this)

                        break;

                    else if (parent == null)

                        throw new InvalidParameterException("The root of the element must be this XmlDocument !");

                } while (parent != null);

                this.defaultContainer = container;

            }

        } catch (InvalidParameterException e) {

            e.printStackTrace();

        }

    }

    public Boolean setDefaultContainerByPath(String path) {

        List<Element> elements = getElementsOf(path);

        if (elements == null || elements.size() != 1)

            return false;

        setDefaultContainer(elements.get(0));

        return true;

    }

    /**
     * 
     * If there is a solid defaultContainer, then the child would be appended to
     * it directly.
     * 
     * {@inheritDoc}
     * 
     * 
     * 
     * @see org.easyxml.xml.Element#addChildElement(org.easyxml.xml.Element)
     */

    @Override
    public Element addChildElement(Element child) {

        if (defaultContainer != null)

            defaultContainer.addChildElement(child);

        else

            super.addChildElement(child);

        return this;

    }

    /**
     * 
     * If there is a solid defaultContainer, then the attribute would be
     * appended to it directly.
     * 
     * {@inheritDoc}
     * 
     * 
     * 
     * @see org.easyxml.xml.Element#addAttribute(java.lang.String,
     *      java.lang.String)
     */

    @Override
    public Element addAttribute(String name, String value) {

        try {

            if (defaultContainer != null) {

                defaultContainer.addAttribute(name, value);

            } else {

                super.addAttribute(name, value);

            }

        } catch (SAXException ex) {

            ex.printStackTrace();

        }

        return this;

    }

    /**
     * 
     * If there is a solid defaultContainer, then the attributeName be used to
     * search its attributes first.
     * 
     * {@inheritDoc}
     * 
     * 
     * 
     * @see org.easyxml.xml.Element#getAttributeValue(java.lang.String)
     */

    @Override
    public String getAttributeValue(String attributeName) {

        return (defaultContainer != null)

                ? defaultContainer.getAttributeValue(attributeName)

                : super.getAttributeValue(attributeName);

    }

    /**
     * 
     * If there is a solid defaultContainer, then the path be used to search its
     * attributes/elements first.
     * 
     * {@inheritDoc}
     * 
     * 
     * 
     * @see org.easyxml.xml.Element#getElementsOf(java.lang.String)
     */

    @Override
    public List<Element> getElementsOf(String path) {

        List<Element> result = null;

        if (defaultContainer != null) {

            result = defaultContainer.getElementsOf(path);

            if (result != null)

                return result;

        }

        return super.getElementsOf(path);

    }

    /**
     * 
     * If there is a solid defaultContainer, then the path be used to search its
     * attributes/elements first.
     * 
     * {@inheritDoc}
     * 
     * 
     * 
     * @see org.easyxml.xml.Element#getValuesOf(java.lang.String)
     */

    @Override
    public String[] getValuesOf(String path) {

        return (defaultContainer != null) ?

                defaultContainer.getValuesOf(path) : super.getValuesOf(path);

    }

    /**
     * 
     * If there is a solid defaultContainer, then the path be used to search its
     * attributes/elements first.
     * 
     * {@inheritDoc}
     * 
     * 
     * 
     * @see org.easyxml.xml.Element#setValuesOf(java.lang.String,
     *      java.lang.String[])
     */

    @Override
    public Boolean setValuesOf(String path, String... values) {

        return (defaultContainer != null) ?

                defaultContainer.setValuesOf(path, values) : super.setValuesOf(path, values);

    }

    /**
     * 
     * If there is a solid defaultContainer, then the attributeName be used to
     * search its attributes/elements first.
     * 
     * {@inheritDoc}
     * 
     * 
     * 
     * @see org.easyxml.xml.Element#setAttributeValue(java.lang.String,
     *      java.lang.String)
     */

    @Override
    public Boolean setAttributeValue(String attributeName, String newValue) {

        return (defaultContainer != null) ?

                defaultContainer.setAttributeValue(attributeName, newValue)
                : super.setAttributeValue(attributeName, newValue);

    }

    @Override
    public Boolean containsElement(String name) {

        Boolean result = false;

        if (defaultContainer != null) {

            result = defaultContainer.containsElement(name);

            if (result)

                return result;

        }

        return super.containsElement(name);

    }

    @Override
    public String toString() {

        return this.toString(DefaultCharset, DefaultDisplayEmeptyElement, DefaultDisplayEmeptyElement);

    }

    /**
     * 
     * Get well-formatted string of this XML document.
     * 
     * @param charset
     *            - Charset to be specified in the XML Declaration.
     * 
     * @param keepEmptyElments
     *            - Specify if Empty Elements shall be displayed.
     * 
     * @param keepSpace
     *            - Specify if SPACE like ' ', '\t', '\n' shall be displayed.
     * 
     * @return Output string.
     */

    public String toString(Charset charset, Boolean keepEmptyElments, Boolean keepSpace) {

        if (charset == null) {

            System.out.print("Invalid charset specified, using the Default Charset instead.");

            charset = DefaultCharset;

        }

        String xml = String.format(DefaultDeclarationFormat, charset.name()) +

                super.toString(0, keepEmptyElments, keepEmptyElments);

        if (!keepSpace) {

            xml = xml.replaceAll("\\s+", "");

        }

        return xml;

    }

    /**
     * 
     * Get the byte array of this XmlDocument.
     * 
     * @param charset
     *            - Charset to be specified in the XML Declaration.
     * 
     * @param keepEmptyElments
     *            - Specify if Empty Elements shall be displayed.
     * 
     * @param keepSpace
     *            - Specify if SPACE like ' ', '\t', '\n' shall be displayed.
     * 
     * @return Output byte array by chosen charset.
     */

    public byte[] getBytes(Charset charset, Boolean keepEmptyElments, Boolean keepSpace) {

        String xml = this.toString(charset, keepEmptyElments, keepSpace);

        byte[] bytes = xml.getBytes(charset);

        return bytes;

    }

    /**
     * 
     * Extract values of this document.
     * 
     * @param pathMap
     *            - A map of the display name (as key) and element path (as
     *            value).
     * 
     * @return Map<String, String[]> instance whose key stores the display name,
     *         and its value keeps all values of whose path.
     */

    public Map<String, String[]> extractValues(Map<String, String> pathMap) {

        if (pathMap == null)

            return null;

        Map<String, String[]> result = new LinkedHashMap<String, String[]>();

        Iterator<Entry<String, String>> iterator = pathMap.entrySet().iterator();

        while (iterator.hasNext()) {

            Entry<String, String> next = iterator.next();

            String path = next.getKey();

            String[] values = getValuesOf(path);

            result.put(next.getValue(), values);

        }

        return result;

    }

    public List<? extends Map<String, String>> mapOf(String objectPath) {

        return mapOf(objectPath, null);

    }

    public List<? extends Map<String, String>> mapOf(String objectPath, Map<String, String> pathMap) {

        if (objectPath == null || !containsElement(objectPath))

            return null;

        List<Element> objectElements = getElementsOf(objectPath);

        if (pathMap == null) {

            pathMap = new HashMap<String, String>();

            String thisPath = this.defaultContainer == null ? this.getPath() : this.defaultContainer.getPath();

            for (Element element : objectElements) {

                if (element.attributes != null) {

                    for (Map.Entry<String, Attribute> attribute : element.attributes.entrySet()) {

                        String key = attribute.getKey();

                        if (!pathMap.containsKey(key))

                            pathMap.put(key, key);

                    }

                }

                if (element.children != null) {

                    for (Map.Entry<String, List<Element>> child : element.children.entrySet()) {

                        String key = child.getKey();

                        int lastSignPos = StringUtils.lastIndexOfAny(key, Attribute.DefaultAttributePathSign,
                                Element.DefaultElementPathSign);

                        String alias = lastSignPos == -1 ? key : key.substring(lastSignPos + 1);

                        if (!pathMap.containsKey(key))

                            pathMap.put(key, alias);

                    }

                }

            }

        }

        ArrayList<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>();

        for (Element element : objectElements) {

            HashMap<String, String> map = new HashMap<String, String>();

            for (Map.Entry<String, String> entry : pathMap.entrySet()) {

                String[] values = element.getValuesOf(entry.getKey());

                if (values == null || values.length == 0)

                    continue;

                String theValue = (values.length == 1) ? values[0] : "[" + StringUtils.join(values, ", " + "]");

                String theAlias = entry.getValue();

                if (map.containsKey(theAlias)) {

                    theAlias = entry.getKey().replaceAll("<|>", "_");

                }

                map.put(theAlias, theValue);

            }

            result.add(map);

        }

        return result;

    }

    public String toJSON(String objectPath, Map<String, String> pathMap) {

        if (objectPath == null || !containsElement(objectPath) || pathMap == null)

            return null;

        Map<String, String> pathToKeys = new LinkedHashMap<String, String>();

        for (Map.Entry<String, String> entry : pathMap.entrySet()) {

            String key = entry.getKey();

            String originalPath = entry.getValue();

            if (!originalPath.startsWith(objectPath)) {

                continue;

            }

            String relativePath = originalPath.substring(objectPath.length() + 1);

            pathToKeys.put(relativePath, key);

        }

        if (!pathToKeys.containsKey("")) {

            pathToKeys.put("", elementNameOf(objectPath));

        }

        List<Element> objectElements = getElementsOf(objectPath);

        return getJsonStringOf(objectElements, pathToKeys);

    }

    public String toJSON(String objectPath) {

        if (objectPath == null || !containsElement(objectPath))

            return null;

        Map<String, String> pathToKeys = new LinkedHashMap<String, String>();

        for (Map.Entry<String, List<Element>> entry : this.children.entrySet()) {

            String originalPath = entry.getKey();

            if (!originalPath.startsWith(objectPath)) {

                continue;

            }

            String relativePath = originalPath.equals(objectPath) ? ""
                    : originalPath.substring(objectPath.length() + 1);

            String elementName = elementNameOf(originalPath);

            if (!pathToKeys.containsKey(relativePath)) {

                pathToKeys.put(relativePath, elementName);

            } else

                throw new InvalidParameterException("Duplicated definitionf of " + entry);

        }

        List<Element> objectElements = getElementsOf(objectPath);

        return getJsonStringOf(objectElements, pathToKeys);

    }

    @Override
    public String toJSON() {

        if (this.defaultContainer != null) {

            return this.defaultContainer.toJSON();

        } else {

            // Map<String, String> pathToKeys = new LinkedHashMap<String,
            // String>();

            // List<String> firstLevelPathes = new ArrayList<String>();

            // for(Map.Entry<String, List<Element>> entry :
            // this.children.entrySet()) {

            // String originalPath = entry.getKey();

            // int firstSignPos = StringUtils.indexOfAny(originalPath, '>',
            // '<');

            //

            // String elementName = elementNameOf(originalPath);

            // if (firstSignPos == -1) {

            // firstLevelPathes.add(originalPath);

            // } else {

            // String relativePath = originalPath.substring(firstSignPos+1);

            // pathToKeys.put(relativePath, elementName);

            // }

            // }

            //

            // List<Element> objectElements = new ArrayList<Element>();

            // for(String firstLevelPath : firstLevelPathes) {

            // List<Element> elements = this.getElementsOf(firstLevelPath);

            // objectElements.addAll(elements);

            // }

            // return getJsonStringOf(objectElements, pathToKeys);

            return super.toJSON();

        }

    }

}