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

deepdiff.scope.XMLDiffScope Maven / Gradle / Ivy

There is a newer version: 1.0.2
Show newest version
/*
 * Copyright 2011 DeepDiff Contributors
 *
 * 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 deepdiff.scope;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;

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

import org.apache.log4j.Logger;

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

import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import deepdiff.core.DiffPointProcessor;
import deepdiff.core.DiffScope;
import deepdiff.core.DiffUnit;
import deepdiff.core.DiffUnitProcessor;

/**
 * An implementation of DiffScope that takes an XML file and expands it into
 * DiffUnits for each node using DOM.
 */
public class XMLDiffScope implements DiffScope {
    private static final Logger log = Logger.getLogger(XMLDiffScope.class);

    private DocumentBuilderFactory dbf;

    private InputStream is1;
    private InputStream is2;

    private String path;

    /**
     * Initializes a new XMLDiffScope object.
     *
     * @param path the scoped path to the XML file
     * @param is1 the input stream for the XML file on the left
     * @param is2 the input stream for the XML file on the right
     */
    public XMLDiffScope(String path, InputStream is1, InputStream is2) {
        this.path = path;
        this.is1 = is1;
        this.is2 = is2;
        dbf = DocumentBuilderFactory.newInstance();
        dbf.setCoalescing(true);
        dbf.setExpandEntityReferences(false);
        dbf.setNamespaceAware(true);
        dbf.setValidating(false);
    }

    /**
     * Scans the XML files for DiffUnits and processes them
     *
     * @param unitProcessor the unit processor to process the DiffUnits found in
     *                      the scan
     * @param pointProcessor the point processor to pass to the unit processor
     *                       when processing units
     */
    public void scan(DiffUnitProcessor unitProcessor,
                     DiffPointProcessor pointProcessor) {
        log.debug("Starting to scan scope " + path);
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            db.setEntityResolver(new EntityResolver() {
                    public InputSource resolveEntity(String publicId,
                                                     String systemId)
                                              throws SAXException, IOException {
                        return new InputSource(
                                new ByteArrayInputStream(
                                    new byte[0]));
                    }
                });

            Document d1 = db.parse(is1);
            Document d2 = db.parse(is2);
            scan(d1, d2, unitProcessor, pointProcessor);
        } catch (ParserConfigurationException pce) {
            log.error("Failure scanning scope " + path, pce);
        } catch (SAXException saxe) {
            log.error("Malformed XML file: " + path, saxe);
        } catch (IOException ioe) {
            log.error("Failure scanning scope " + path, ioe);
        } finally {
            if (is1 != null) {
                try {
                    is1.close();
                } catch (Exception ex) {
                    //Ignore exception on close
                }
            }
            if (is2 != null) {
                try {
                    is2.close();
                } catch (Exception ex) {
                    //Ignore exception on close
                }
            }
        }
        log.debug("Completed scan of scope " + path);
    }

    /**
     * Scans the XML Documents for DiffUnits and processes them
     *
     * @param d1 the Document on the left
     * @param d2 the Document on the right
     * @param unitProcessor the unit processor to process the DiffUnits found in
     *                      the scan
     * @param pointProcessor the point processor to pass to the unit processor
     *                       when processing units
     */
    private void scan(Document d1, Document d2, DiffUnitProcessor unitProcessor,
                      DiffPointProcessor pointProcessor) {
        XMLDocumentDiffUnit diffUnit = new XMLDocumentDiffUnit(this, d1, d2);
        String scopedPath = diffUnit.getScopedPath();
        log.debug("Processing " + scopedPath);
        unitProcessor.processDiffUnit(diffUnit, pointProcessor);
        Element de1 = d1.getDocumentElement();
        Element de2 = d2.getDocumentElement();
        scan(diffUnit, 0, de1, de2, unitProcessor, pointProcessor);
    }

    /**
     * Scans the Nodes for DiffUnits and processes them
     *
     * @param parentUnit the parent unit, used for assembling the scoped path
     * @param index the index of the node among its siblings, used for
     *              assembling the scoped path
     * @param n1 the Node on the left
     * @param n2 the Node on the right
     * @param unitProcessor the unit processor to process the DiffUnits found in
     *                      the scan
     * @param pointProcessor the point processor to pass to the unit processor
     *                       when processing units
     */
    private void scan(DiffUnit parentUnit, int index, Node n1, Node n2,
                      DiffUnitProcessor unitProcessor,
                      DiffPointProcessor pointProcessor) {
        XMLNodeDiffUnit diffUnit =
            new XMLNodeDiffUnit(parentUnit, index, n1, n2);
        log.debug("Processing " + diffUnit.getScopedPath());
        unitProcessor.processDiffUnit(diffUnit, pointProcessor);
        scanAttributes(diffUnit, n1, n2, unitProcessor, pointProcessor);
        NodeList children1 = n1.getChildNodes();
        NodeList children2 = n2.getChildNodes();
        int len1 = children1.getLength();
        int len2 = children2.getLength();
        // TODO: support comparison of nodes with mismatched child lengths
        if (len1 != len2) {
            log.error(diffUnit.getScopedPath() + ": Mismatch child length: "
                + len1 + ", " + len2
                + "; detailed processing not yet supported");
        } else {
            for (int i = 0; i < len1; i++) {
                Node child1 = children1.item(i);
                Node child2 = children2.item(i);
                scan(diffUnit, i, child1, child2, unitProcessor,
                    pointProcessor);
            }
        }
    }

    /**
     * Scans the attributes for the specified Nodes for DiffUnits and processes
     * them
     *
     * @param elementUnit the DiffUnit for the element that contains the
     *                    attributes
     * @param n1 the Node on the left
     * @param n2 the Node on the right
     * @param unitProcessor the unit processor to process the DiffUnits found in
     *                      the scan
     * @param pointProcessor the point processor to pass to the unit processor
     *                       when processing units
     */
    private void scanAttributes(XMLNodeDiffUnit elementUnit, Node n1, Node n2,
                                DiffUnitProcessor unitProcessor,
                                DiffPointProcessor pointProcessor) {
        NamedNodeMap a1 = n1.getAttributes();
        NamedNodeMap a2 = n2.getAttributes();
        if (a1 == null && a2 == null) {
            // No attributes for this node
            return;
        }
        SortedSet names = new TreeSet();
        if (a1 != null) {
            for (int i = 0; i < a1.getLength(); i++) {
                names.add(a1.item(i).getNodeName());
            }
        }
        if (a2 != null) {
            for (int i = 0; i < a2.getLength(); i++) {
                names.add(a2.item(i).getNodeName());
            }
        }
        for (Iterator it = names.iterator(); it.hasNext();) {
            String name = (String) it.next();
            Node an1 = null;
            Node an2 = null;
            if (a1 != null) {
                an1 = a1.getNamedItem(name);
            }
            if (a2 != null) {
                an2 = a2.getNamedItem(name);
            }
            DiffUnit diffUnit =
                new XMLAttributeDiffUnit(elementUnit, name, an1, an2);
            log.debug("Processing " + diffUnit.getScopedPath());
            unitProcessor.processDiffUnit(diffUnit, pointProcessor);
        }
    }

    /**
     * Returns the path of the scope
     *
     * @return the path of the scope
     */
    public String getPath() {
        return path;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy