com.nridge.core.base.io.xml.DocumentXML.java Source code

Java tutorial

Introduction

Here is the source code for com.nridge.core.base.io.xml.DocumentXML.java

Source

/*
 * NorthRidge Software, LLC - Copyright (c) 2019.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.nridge.core.base.io.xml;

import com.nridge.core.base.doc.Document;
import com.nridge.core.base.doc.Relationship;
import com.nridge.core.base.io.IO;
import com.nridge.core.base.std.StrUtl;
import com.nridge.core.base.std.XMLUtl;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * The DocumentXML provides a collection of methods that can generate/load
 * an XML representation of a {@link com.nridge.core.base.doc.Document} object.
 *
 * @since 1.0
 * @author Al Cole
 */
public class DocumentXML implements DOMInterface {
    private boolean mIsSimple;
    private Document mDocument;
    private boolean mSaveFieldsWithoutValues;

    /**
     * Default constructor.
     */
    public DocumentXML() {
        mDocument = new Document(IO.XML_DOCUMENT_NODE_NAME);
    }

    /**
     * Constructor accepts a document as a parameter.
     *
     * @param aDocument Document instance.
     */
    public DocumentXML(Document aDocument) {
        mDocument = aDocument;
    }

    /**
     * Assigns a {@link Document}.  This should be done via
     * a constructor or this method prior to a save method
     * being invoked.
     *
     * @param aDocument Document instance.
     */
    public void setDocument(Document aDocument) {
        mDocument = aDocument;
    }

    /**
     * Returns a reference to the {@link Document} that this
     * class is managing.
     *
     * @return Document instance.
     */
    public Document getDocument() {
        return mDocument;
    }

    /**
     * Assigns a simple format flag.
     *
     * @param anIsSimple Is output format simple?
     */
    public void setIsSimpleFlag(boolean anIsSimple) {
        mIsSimple = anIsSimple;
    }

    /**
     * Assigning this to <i>true</i> will ensure all fields are written
     * (regardless of them having values assigned).  Use this method
     * to generate schema files.
     *
     * @param aFlag <i>true</i> or <i>false</i>
     */
    public void setSaveFieldsWithoutValues(boolean aFlag) {
        mSaveFieldsWithoutValues = aFlag;
    }

    /**
     * Saves the previous assigned document (e.g. via constructor or set method)
     * to the print writer stream wrapped in a tag name specified in the parameter.
     *
     * @param aPW            PrintWriter stream instance.
     * @param aParentTag     Parent tag name.
     * @param aDocument      Document instance.
     * @param anIndentAmount Indentation count.
     *
     * @throws java.io.IOException I/O related exception.
     */
    public void save(PrintWriter aPW, String aParentTag, Document aDocument, int anIndentAmount)
            throws IOException {
        RelationshipXML relationshipXML;
        String docType = StringUtils.remove(aDocument.getType(), StrUtl.CHAR_SPACE);
        String parentTag = StringUtils.remove(aParentTag, StrUtl.CHAR_SPACE);

        IOXML.indentLine(aPW, anIndentAmount);
        if (StringUtils.isNotEmpty(aParentTag))
            aPW.printf("<%s-%s", parentTag, docType);
        else
            aPW.printf("<%s", docType);
        if (!mIsSimple) {
            IOXML.writeAttrNameValue(aPW, "type", aDocument.getType());
            IOXML.writeAttrNameValue(aPW, "name", aDocument.getName());
            IOXML.writeAttrNameValue(aPW, "title", aDocument.getTitle());
            IOXML.writeAttrNameValue(aPW, "schemaVersion", aDocument.getSchemaVersion());
        }
        for (Map.Entry<String, String> featureEntry : aDocument.getFeatures().entrySet())
            IOXML.writeAttrNameValue(aPW, featureEntry.getKey(), featureEntry.getValue());
        aPW.printf(">%n");
        DataTableXML dataTableXML = new DataTableXML(aDocument.getTable());
        dataTableXML.setSaveFieldsWithoutValues(mSaveFieldsWithoutValues);
        dataTableXML.save(aPW, IO.XML_TABLE_NODE_NAME, anIndentAmount + 1);
        if (aDocument.relationshipCount() > 0) {
            ArrayList<Relationship> docRelationships = aDocument.getRelationships();
            IOXML.indentLine(aPW, anIndentAmount + 1);
            aPW.printf("<%s>%n", IO.XML_RELATED_NODE_NAME);
            for (Relationship relationship : docRelationships) {
                relationshipXML = new RelationshipXML(relationship);
                relationshipXML.setSaveFieldsWithoutValues(mSaveFieldsWithoutValues);
                relationshipXML.save(aPW, IO.XML_RELATIONSHIP_NODE_NAME, anIndentAmount + 2);
            }
            IOXML.indentLine(aPW, anIndentAmount + 1);
            aPW.printf("</%s>%n", IO.XML_RELATED_NODE_NAME);
        }
        HashMap<String, String> docACL = aDocument.getACL();
        if (docACL.size() > 0) {
            IOXML.indentLine(aPW, anIndentAmount + 1);
            aPW.printf("<%s>%n", IO.XML_ACL_NODE_NAME);
            for (Map.Entry<String, String> aclEntry : docACL.entrySet()) {
                IOXML.indentLine(aPW, anIndentAmount + 2);
                aPW.printf("<%s", IO.XML_ACE_NODE_NAME);
                IOXML.writeAttrNameValue(aPW, "name", aclEntry.getKey());
                aPW.printf(">%s</%s>%n", StringEscapeUtils.escapeXml10(aclEntry.getValue()), IO.XML_ACE_NODE_NAME);
            }
            IOXML.indentLine(aPW, anIndentAmount + 1);
            aPW.printf("</%s>%n", IO.XML_ACL_NODE_NAME);
        }
        IOXML.indentLine(aPW, anIndentAmount);
        if (StringUtils.isNotEmpty(aParentTag))
            aPW.printf("</%s-%s>%n", parentTag, docType);
        else
            aPW.printf("</%s>%n", docType);
    }

    /**
     * Saves the previous assigned document (e.g. via constructor or set method)
     * to the print writer stream wrapped in a tag name specified in the parameter.
     *
     * @param aPW            PrintWriter stream instance.
     * @param aTagName       Tag name.
     * @param anIndentAmount Indentation count.
     * @throws java.io.IOException I/O related exception.
     */
    @Override
    public void save(PrintWriter aPW, String aTagName, int anIndentAmount) throws IOException {
        save(aPW, aTagName, mDocument, anIndentAmount);
    }

    /**
     * Saves the previous assigned document (e.g. via constructor or set method)
     * to the print writer stream specified as a parameter.
     *
     * @param aPW PrintWriter stream instance.
     * @throws java.io.IOException I/O related exception.
     */
    @Override
    public void save(PrintWriter aPW) throws IOException {
        save(aPW, StringUtils.EMPTY, mDocument, 0);
    }

    /**
     * Saves the previous assigned document (e.g. via constructor or set method)
     * to the path/file name specified as a parameter.
     *
     * @param aPathFileName Absolute file name.
     * @throws java.io.IOException I/O related exception.
     */
    @Override
    public void save(String aPathFileName) throws IOException {
        try (PrintWriter printWriter = new PrintWriter(aPathFileName, StrUtl.CHARSET_UTF_8)) {
            save(printWriter);
        }
    }

    private void loadRelated(Document aDocument, Element anElement) throws IOException {
        Node nodeItem;
        String nodeName;
        Element nodeElement;
        RelationshipXML relationshipXML;

        ArrayList<Relationship> docRelationships = aDocument.getRelationships();
        NodeList nodeList = anElement.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            nodeItem = nodeList.item(i);

            if (nodeItem.getNodeType() == Node.ELEMENT_NODE) {
                nodeName = nodeItem.getNodeName();
                if (StringUtils.equalsIgnoreCase(nodeName, IO.XML_RELATIONSHIP_NODE_NAME)) {
                    nodeElement = (Element) nodeItem;
                    relationshipXML = new RelationshipXML();
                    relationshipXML.load(nodeElement);
                    docRelationships.add(relationshipXML.getRelationship());
                }
            }
        }
    }

    private void loadACL(Document aDocument, Element anElement) throws IOException {
        Node nodeItem;
        Element nodeElement;
        String nodeName, aceName, aceValue;

        HashMap<String, String> docACL = aDocument.getACL();
        NodeList nodeList = anElement.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            nodeItem = nodeList.item(i);

            if (nodeItem.getNodeType() == Node.ELEMENT_NODE) {
                nodeName = nodeItem.getNodeName();
                if (StringUtils.equalsIgnoreCase(nodeName, IO.XML_ACE_NODE_NAME)) {
                    nodeElement = (Element) nodeItem;
                    aceName = nodeElement.getAttribute("name");
                    aceValue = XMLUtl.getNodeStrValue(nodeItem);
                    docACL.put(aceName, aceValue);
                }
            }
        }
    }

    private Document loadDocument(Element anElement) throws IOException {
        Node nodeItem;
        Attr nodeAttr;
        Document document;
        Element nodeElement;
        String nodeName, nodeValue;

        String docName = anElement.getAttribute("name");
        String typeName = anElement.getAttribute("type");
        String docTitle = anElement.getAttribute("title");
        String schemaVersion = anElement.getAttribute("schemaVersion");
        if ((StringUtils.isNotEmpty(typeName)) && (StringUtils.isNotEmpty(schemaVersion)))
            document = new Document(typeName);
        else
            document = new Document("Unknown");
        if (StringUtils.isNotEmpty(docName))
            document.setName(docName);
        if (StringUtils.isNotEmpty(docTitle))
            document.setName(docTitle);

        NamedNodeMap namedNodeMap = anElement.getAttributes();
        int attrCount = namedNodeMap.getLength();
        for (int attrOffset = 0; attrOffset < attrCount; attrOffset++) {
            nodeAttr = (Attr) namedNodeMap.item(attrOffset);
            nodeName = nodeAttr.getNodeName();
            nodeValue = nodeAttr.getNodeValue();

            if (StringUtils.isNotEmpty(nodeValue)) {
                if ((StringUtils.equalsIgnoreCase(nodeName, "name"))
                        || (StringUtils.equalsIgnoreCase(nodeName, "type"))
                        || (StringUtils.equalsIgnoreCase(nodeName, "title"))
                        || (StringUtils.equalsIgnoreCase(nodeName, "schemaVersion")))
                    continue;
                else
                    document.addFeature(nodeName, nodeValue);
            }
        }

        NodeList nodeList = anElement.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            nodeItem = nodeList.item(i);

            if (nodeItem.getNodeType() != Node.ELEMENT_NODE)
                continue;

            nodeName = nodeItem.getNodeName();
            if (StringUtils.equalsIgnoreCase(nodeName, IO.XML_TABLE_NODE_NAME)) {
                nodeElement = (Element) nodeItem;
                DataTableXML dataTableXML = new DataTableXML();
                dataTableXML.load(nodeElement);
                document.setTable(dataTableXML.getTable());
            } else if (StringUtils.equalsIgnoreCase(nodeName, IO.XML_RELATED_NODE_NAME)) {
                nodeElement = (Element) nodeItem;
                loadRelated(document, nodeElement);
            } else if (StringUtils.equalsIgnoreCase(nodeName, IO.XML_ACL_NODE_NAME)) {
                nodeElement = (Element) nodeItem;
                loadACL(document, nodeElement);
            }
        }

        return document;
    }

    /**
     * Parses an XML DOM element and loads it into a document.
     *
     * @param anElement DOM element.
     * @throws java.io.IOException I/O related exception.
     */
    @Override
    public void load(Element anElement) throws IOException {
        mDocument = loadDocument(anElement);
    }

    /**
     * Parses an XML DOM element and loads it into a document.
     *
     * @param anIS Input stream.
     * @throws java.io.IOException                            I/O related exception.
     * @throws javax.xml.parsers.ParserConfigurationException XML parser related exception.
     * @throws org.xml.sax.SAXException                       XML parser related exception.
     */
    @Override
    public void load(InputStream anIS)
            throws ParserConfigurationException, IOException, SAXException, TransformerException {
        DocumentBuilderFactory docBldFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docBldFactory.newDocumentBuilder();
        InputSource inputSource = new InputSource(anIS);
        org.w3c.dom.Document xmlDocument = docBuilder.parse(inputSource);
        xmlDocument.getDocumentElement().normalize();

        load(xmlDocument.getDocumentElement());
    }

    /**
     * Parses an XML file identified by the path/file name parameter
     * and loads it into a document.
     *
     * @param aPathFileName Absolute file name.
     * @throws java.io.IOException                            I/O related exception.
     * @throws javax.xml.parsers.ParserConfigurationException XML parser related exception.
     * @throws org.xml.sax.SAXException                       XML parser related exception.
     */
    @Override
    public void load(String aPathFileName) throws IOException, ParserConfigurationException, SAXException {
        File xmlFile = new File(aPathFileName);
        if (!xmlFile.exists())
            throw new IOException(aPathFileName + ": Does not exist.");

        DocumentBuilderFactory docBldFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docBldFactory.newDocumentBuilder();
        org.w3c.dom.Document xmlDocument = docBuilder.parse(new File(aPathFileName));
        xmlDocument.getDocumentElement().normalize();

        load(xmlDocument.getDocumentElement());
    }
}