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

io.atlasmap.xml.core.XmlFieldReader Maven / Gradle / Ivy

/**
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * 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 io.atlasmap.xml.core;

import io.atlasmap.api.AtlasException;
import io.atlasmap.v2.FieldType;
import io.atlasmap.xml.v2.XmlField;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import io.atlasmap.core.PathUtil;
import io.atlasmap.core.PathUtil.SegmentContext;

public class XmlFieldReader extends XmlFieldTransformer {

    private static final Logger logger = LoggerFactory.getLogger(XmlFieldReader.class);

    public XmlFieldReader() {
    }

    public XmlFieldReader(Map namespaces) {
        super(namespaces);
    }

    public void readNew(final Document document, final XmlField xmlField) throws AtlasException {
        if (logger.isDebugEnabled()) {
            logger.debug("Reading input value for field: " + xmlField.getPath());
        }
        Element parentNode = document.getDocumentElement();
        for (SegmentContext sc : new PathUtil(xmlField.getPath()).getSegmentContexts(false)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Now processing segment: " + sc.getSegment());
                logger.debug("Parent element is currently: " + XmlFieldWriter.writeDocumentToString(true, parentNode));
            }
            if (sc.getPrev() == null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping root segment: " + sc);
                }
                // processing root node part of path such as the "XOA" part of
                // "/XOA/contact<>/firstName", skip.
                continue;
            }

            if (!PathUtil.isAttributeSegment(sc.getSegment())) {
                String childrenElementName = PathUtil.cleanPathSegment(sc.getSegment());
                String namespaceAlias = PathUtil.getNamespace(sc.getSegment());
                if (namespaceAlias != null && !"".equals(namespaceAlias)) {
                    childrenElementName = namespaceAlias + ":" + childrenElementName;
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Looking for children elements with name: " + childrenElementName);
                }
                List children = XmlFieldWriter.getChildrenWithName(childrenElementName, parentNode);
                if (children == null || children.isEmpty()) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipping input value set, couldn't find children with name '"
                                + childrenElementName + "', for segment: " + sc);
                    }
                    return;
                }
                parentNode = children.get(0);
                if (PathUtil.isCollectionSegment(sc.getSegment())) {
                    int index = PathUtil.indexOfSegment(sc.getSegment());
                    if (index >= children.size()) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Skipping input value set, children list can't fit index " + index
                                    + ", children list size: " + children.size());
                        }
                        return;
                    }
                    parentNode = children.get(index);
                }
            }
            if (sc.getNext() == null) { // last segment.
                String value = parentNode.getTextContent();
                if (PathUtil.isAttributeSegment(sc.getSegment())) {
                    String attributeName = PathUtil.cleanPathSegment(sc.getSegment());
                    value = parentNode.getAttribute(attributeName);
                }
                if (xmlField.getFieldType() == null || FieldType.STRING.equals(xmlField.getFieldType())) {
                    xmlField.setValue(value);
                    xmlField.setFieldType(FieldType.STRING);
                } else if (FieldType.CHAR.equals(xmlField.getFieldType())) {
                    xmlField.setValue(value.charAt(0));
                }

                if (value != null) {
                    if (FieldType.BOOLEAN.equals(xmlField.getFieldType())) {
                        xmlField.setValue(processXmlStringAsBoolean(value));
                    } else {
                        logger.warn(String.format("Unsupported FieldType for text data t=%s p=%s docId=%s",
                                xmlField.getFieldType().value(), xmlField.getPath(), xmlField.getDocId()));
                    }
                }
                return;
            }
        }
    }

    public void read(final Document document, final XmlField xmlField) throws AtlasException {
        if (document == null) {
            throw new AtlasException(new IllegalArgumentException("Argument 'document' cannot be null"));
        }
        if (xmlField == null) {
            throw new AtlasException(new IllegalArgumentException("Argument 'xmlField' cannot be null"));
        }

        // check to see if the document has namespaces
        seedDocumentNamespaces(document);
        // read the Document using xmlPath field to set the value on the XmlField
        String xmlPath = xmlField.getPath();
        String attr = null;
        LinkedList elements = getElementsInXmlPath(xmlPath);
        LinkedList xmlPathCoordinates = (LinkedList) createXmlPathCoordinates(
                elements);
        // is the last coordinate an attribute?
        if (xmlPathCoordinates.getLast().getElementName().startsWith("@")) {
            attr = xmlPathCoordinates.getLast().getElementName().replace("@", "").trim();
            xmlPathCoordinates.removeLast();
        }
        // the first coordinate sets the 'root' node including the namespace we are
        // working with...
        XmlPathCoordinate root = xmlPathCoordinates.getFirst();
        NodeList nodes = getNodeList(document, root);
        Node node = nodes.item(root.getIndex());
        if (node != null) {
            // find the (grand)child node that has the value to set
            for (XmlPathCoordinate xmlPathCoordinate : xmlPathCoordinates.subList(1, xmlPathCoordinates.size())) {
                node = getChildNodeForRead(node, xmlPathCoordinate);
            }
            if (node != null && node.getNodeType() == Node.ELEMENT_NODE) {
                Element e = (Element) node;
                String value;
                if (attr != null) {
                    if (attr.contains(":")) {
                        String[] attrSplit = attr.split(":");
                        String namespace = findNamespaceURIFromPrefix(attrSplit[0]);
                        value = e.getAttributeNS(namespace, attrSplit[1]);
                    } else {
                        value = e.getAttribute(attr);
                    }
                } else {
                    value = e.getTextContent();
                }
                if (xmlField.getFieldType() == null || FieldType.STRING.equals(xmlField.getFieldType())) {
                    xmlField.setValue(value);
                    xmlField.setFieldType(FieldType.STRING);
                } else if (FieldType.CHAR.equals(xmlField.getFieldType())) {
                    xmlField.setValue(value.charAt(0));
                }

                if (value != null) {
                    if (FieldType.BOOLEAN.equals(xmlField.getFieldType())) {
                        xmlField.setValue(processXmlStringAsBoolean(value));
                    } else {
                        logger.warn(String.format("Unsupported FieldType for text data t=%s p=%s docId=%s",
                                xmlField.getFieldType().value(), xmlField.getPath(), xmlField.getDocId()));
                    }
                }
            }
        }
    }

    public static Boolean processXmlStringAsBoolean(String value) {
        if (value == null) {
            return null;
        }

        if ("true".equalsIgnoreCase(value) || "1".equalsIgnoreCase(value)) {
            return Boolean.TRUE;
        }

        if ("false".equalsIgnoreCase(value) || "0".equalsIgnoreCase(value)) {
            return Boolean.FALSE;
        }

        return null;
    }

    public void read(final Document document, final List xmlFields) throws AtlasException {
        if (xmlFields == null) {
            throw new AtlasException(new IllegalArgumentException("Argument 'xmlFields' cannot be null"));
        }
        // check to see if the document has namespaces
        seedDocumentNamespaces(document);
        for (XmlField xmlField : xmlFields) {
            read(document, xmlField);
        }
    }

    private Node getChildNodeForRead(final Node node, final XmlPathCoordinate xmlPathCoordinate) {
        if (!node.hasChildNodes() || node.getNodeType() != Node.ELEMENT_NODE) {
            return node;
        }
        Node returnNode;
        Map.Entry namespace = null;
        Element element = (Element) node;
        String childName = xmlPathCoordinate.getElementName();
        if (xmlPathCoordinate.getNamespace() != null) {
            namespace = xmlPathCoordinate.getNamespace().entrySet().iterator().next();
        }
        if (childName.contains(":")) {
            childName = childName.substring(childName.indexOf(":") + 1, childName.length());
        }
        if (namespace != null) {
            returnNode = element.getElementsByTagNameNS(namespace.getKey(), childName)
                    .item(xmlPathCoordinate.getIndex());
        } else {
            returnNode = element.getElementsByTagName(childName).item(xmlPathCoordinate.getIndex());
        }
        return returnNode;
    }

    private NodeList getNodeList(Document document, XmlPathCoordinate root) {
        NodeList nodes = null;
        // if the document does not have namespacing but the paths do....
        if ((namespaces != null && namespaces.isEmpty())
                && (root.getElementName().contains(":") && root.getNamespace() == null)) {
            // strip out the namespace from the root coordinate path
            String correctedElement = root.getElementName().substring(root.getElementName().indexOf(":") + 1,
                    root.getElementName().length());
            nodes = document.getElementsByTagName(correctedElement);
        } else if ((namespaces != null && !namespaces.isEmpty())
                && (!root.getElementName().contains(":") && root.getNamespace() == null)) {
            // if the document has namespaces but the paths don't
            for (Map.Entry namespaceEntry : namespaces.entrySet()) {
                root.setNamespace(namespaceEntry.getKey(), namespaceEntry.getValue());
                nodes = document.getElementsByTagNameNS(namespaceEntry.getKey(), root.getElementName());
                // we found the element with the namespace
                if (nodes.getLength() > 0) {
                    break;
                }
            }
        } else {
            // default to find nodes without namespaces
            nodes = document.getElementsByTagName(root.getElementName());
        }
        return nodes;
    }

    public Integer getCollectionCount(Document document, XmlField xmlField, String collectionSegment)
            throws AtlasException {
        if (document == null) {
            throw new AtlasException(new IllegalArgumentException("Argument 'document' cannot be null"));
        }
        if (xmlField == null) {
            throw new AtlasException(new IllegalArgumentException("Argument 'xmlField' cannot be null"));
        }

        // check to see if the document has namespaces
        seedDocumentNamespaces(document);
        // read the Document using xmlPath field to set the value on the XmlField
        String xmlPath = xmlField.getPath();
        LinkedList elements = getElementsInXmlPath(xmlPath);
        LinkedList xmlPathCoordinates = (LinkedList) createXmlPathCoordinates(
                elements);
        // is the last coordinate an attribute?
        if (xmlPathCoordinates.getLast().getElementName().startsWith("@")) {
            xmlPathCoordinates.removeLast();
        }
        // the first coordinate sets the 'root' node including the namespace we are
        // working with...
        for (XmlPathCoordinate xc : xmlPathCoordinates) {
            if (xc.getElementName().equals(collectionSegment)) {
                NodeList nodes = getNodeList(document, xc);
                return Integer.valueOf(nodes.getLength());
            }
        }

        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy