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

org.enhydra.xml.xmlc.compiler.EditDOM Maven / Gradle / Ivy

The newest version!
/*
 * Enhydra Java Application Server Project
 * 
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License on
 * the Enhydra web site ( http://www.enhydra.org/ ).
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
 * the License for the specific terms governing rights and limitations
 * under the License.
 * 
 * The Initial Developer of the Enhydra Application Server is Lutris
 * Technologies, Inc. The Enhydra Application Server and portions created
 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * $Id: EditDOM.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
 */

package org.enhydra.xml.xmlc.compiler;

import org.enhydra.xml.xmlc.XMLCException;
import org.enhydra.xml.xmlc.dom.XMLCDocument;
import org.enhydra.xml.xmlc.metadata.DOMEdits;
import org.enhydra.xml.xmlc.metadata.DeleteElement;
import org.enhydra.xml.xmlc.metadata.ElementEdit;
import org.enhydra.xml.xmlc.metadata.MetaData;
import org.enhydra.xml.xmlc.metadata.URLMapping;
import org.enhydra.xml.xmlc.metadata.URLRegExpMapping;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * Class to perform edits on a DOM.
 */
public class EditDOM {
    /**
     * DOM edits metadata.
     */
    private DeleteElement[] deleteElements;
    private URLMapping[] urlMappings;
    private URLRegExpMapping[] urlRegExpMappings;

    /**
     * Document being edited.
     */
    private XMLCDocument xmlcDocument;

    /**
     * Is this an HTML document?
     */
    private boolean isHtml;

    /**
     * Constructor.
     */
    public EditDOM(MetaData metaData) {
        DOMEdits domEdits = metaData.getDOMEdits();
        if (domEdits != null) {
            deleteElements = domEdits.getDeleteElements();
            urlMappings = domEdits.getURLMappings();
            urlRegExpMappings = domEdits.getURLRegExpMappings();
        }
        // Default null ones to empty arrays.
        if (deleteElements == null) {
            deleteElements = new DeleteElement[0];
        }
        if (urlMappings == null) {
            urlMappings = new URLMapping[0];
        }
        if (urlRegExpMappings == null) {
            urlRegExpMappings = new URLRegExpMapping[0];
        }
    }

    /**
     * Determine if an element matches an ElementEdit set of constraints.
     */
    private boolean elementMatchesConstraints(Element element,
                                              ElementEdit elementEdit) {
        if (!elementEdit.matchesElementIdConstraints(getElementId(element))) {
            return false;
        }
        String[] elementClasses = xmlcDocument.getElementClassNames(element);
        if (elementClasses == null) {
            // Not classes, must be no class constraints
            if (!elementEdit.matchesElementClassConstraints(null)) {
                return false;
            }
        } else { 
            // At least one class must match.
            boolean classMatched = false;
            for (int idx = 0; (idx < elementClasses.length) && (!classMatched); idx++) {
                if (elementEdit.matchesElementClassConstraints(elementClasses[idx])) {
                    classMatched = true;
                }
            }
            if (!classMatched) {
                return false;
            }
        }
        
        if (!elementEdit.matchesElementTagConstraints(element.getTagName(),
                                                      isHtml)) {
            return false;
        }

        // Passed all constraints.
        return true;
    }

    /**
     * Process a delete element request on an element,
     * @return true if the element is deleted.
     */
    private boolean processDeleteElement(Element element,
                                         DeleteElement deleteElement) {
        if (elementMatchesConstraints(element, deleteElement)) {
            element.getParentNode().removeChild(element);
            return true;
        }
        return false;
    }

    /**
     * Process delete element requests on an element,
     * @return true if the element is deleted.
     */
    private boolean processDeleteElements(Element element) {
        for (int idx = 0; idx < deleteElements.length; idx++) {
            if (processDeleteElement(element, deleteElements[idx])) {
                return true;
            }
        }
        return false;
    }

    /**
     * Process a URL mapping for an attribute.
     *
     * @return true if the attribute was modified, false if it was not.
     */
    private boolean processURLMapping(Element element,
                                      String attrName,
                                      String oldURL,
                                      URLMapping urlMapping) {
        if (elementMatchesConstraints(element, urlMapping)
            && urlMapping.matchesEditAttrConstraints(attrName, isHtml)) {
            // Note: unspecified URL matches all
            String url = urlMapping.getUrl();
            if ((url == null) || url.equals(oldURL)) {
                element.setAttribute(attrName, urlMapping.getNewUrl());
                return true;
            }
        }
        return false;
    }

    /**
     * Process URL mappings for an attribute.
     *
     * @return true if the attribute was modified, false if it was not.
     */
    private boolean processURLMappings(Element element,
                                       String attrName,
                                       String oldURL) {
        for (int idx = 0; idx < urlMappings.length; idx++) {
            if (processURLMapping(element, attrName, oldURL, urlMappings[idx])) {
                return true;
            }
        }
        return false;
    }

    /**
     * Process a URL regexp mapping for an attribute.
     *
     * @return true if the attribute was modified, false if it was not.
     */
    private boolean processURLRegExpMapping(Element element,
                                            String attrName,
                                            String oldURL,
                                            URLRegExpMapping urlRegExpMapping)
            throws XMLCException {
        if (elementMatchesConstraints(element, urlRegExpMapping)
            && urlRegExpMapping.matchesEditAttrConstraints(attrName, isHtml)) {
            String newURL = urlRegExpMapping.mapURL(oldURL);
            if (newURL != null) {
                element.setAttribute(attrName, newURL);
                return true;
            }
        }
        return false;
    }

    /**
     * Process the URL regexp mappings for an attribute.
     *
     * @return true if the attribute was modified, false if it was not.
     */
    private boolean processURLRegExpMappings(Element element,
                                             String attrName,
                                             String oldURL)
            throws XMLCException {
        for (int idx = 0; idx < urlRegExpMappings.length; idx++) {
            if (processURLRegExpMapping(element, attrName, oldURL,
                                        urlRegExpMappings[idx])) {
                return true;
            }
        }
        return false;
    }

    /**
     * Perform URL edits on an attribute element.  Trys URLMappings first,
     * then URL regexp mappings.
     */
    private void editElementURL(Element element,
                                String attrName) throws XMLCException {
        Attr attr = element.getAttributeNode(attrName);
        if ((attr != null) && attr.getSpecified()) {
            String oldURL = attr.getValue();
            if (!processURLMappings(element, attrName, oldURL)) {
                processURLRegExpMappings(element, attrName, oldURL);
            }
        }
    }

    /**
     * Perform URL edits on an element.
     */
    private void editElementURLs(Element element) throws XMLCException {
        NamedNodeMap attrs = element.getAttributes();
        if (attrs != null) {
            for (int idx = 0; idx < attrs.getLength(); idx++) {
                String name = attrs.item(idx).getNodeName();
                if (xmlcDocument.isURLAttribute(element, name)) {
                    editElementURL(element, name);
                }
            }
        }
    }

    /**
     * Recursively edit nodes.
     */
    private void editNodes(Node node)
            throws XMLCException {
        if (node instanceof Element) {
            node = editElement((Element)node);
	    // Don't process the children if editElement() returned null...
	    if (node == null) return;
        }

        // Traverse children
        Node child = node.getFirstChild();
        while (child != null) {
            Node nextChild = child.getNextSibling(); // child might be deleted
            editNodes(child);
            child = nextChild;
        }
    }

    /**
     * Edit a single element. If you override this method, don't
     * forget to call super.editElement(element) to
     * perform the standard edits. Derived classes may replace
     * element by another node in their version of
     * editElement. In this case, the
     * editElement() method must return the new node in order
     * for the editor code to pick up and edit children of this new node.
     * @return element, or null to indicate
     * that the children of this element should not be processed.
     */
    protected Node editElement(Element element) throws XMLCException {
	// Check for deletion first, as no other work will be done if
	// deleted.
	if (processDeleteElements(element)) {
	    return null;
	}
	editElementURLs(element);
	return element;
    }

    /**
     * Edit the nodes of the document.
     */
    public void edit(XMLCDocument xmlcDoc)
            throws XMLCException {
        this.xmlcDocument = xmlcDoc;
        isHtml = xmlcDocument.isHtmlDocument();
        editNodes(xmlcDoc.getDocument());
    }

    /** Get the ID of an element */
    protected String getElementId(Element element) {
	return xmlcDocument.getElementId(element);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy