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

org.enhydra.xml.xmlc.compiler.ElementTable 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: ElementTable.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
 */

package org.enhydra.xml.xmlc.compiler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import org.enhydra.xml.xmlc.XMLCError;
import org.enhydra.xml.xmlc.XMLCException;
import org.enhydra.xml.xmlc.dom.XMLCDocument;
import org.enhydra.xml.xmlc.metadata.MetaData;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * Table of information about each element.
 */
public class ElementTable {
    /**
     * Container for document.
     */
    private XMLCDocument fXmlcDoc;

    /**
     * Metadata object associated with document.
     */
    private MetaData fMetaData;

    /**
     * List of all element info objects, indexed by Element object.
     */
    private Map fElements = new HashMap();

    /**
     * Sorted map of ids to element info.
     */
    private SortedMap fXmlIds = new TreeMap();

    /**
     * Sorted map of Java ids to element info.
     */
    private SortedMap fJavaIds = new TreeMap();

    /**
     * Sorted table of element ids that are not legal Java identifiers.
     * Created when needed.
     */
    private SortedMap fInvalidElementIds;

    /**
     * Is this global-id-attribute mode?
     */
    private boolean fGlobalIdAttrMode;

    /**
     * Table of tag name to id attribute names.  Null in
     * global-id-attribute mode.
     */
    private Map fTagName2IdAttrName;

    /**
     * Table of tag names to Lists of element info objects.
     * Null in global-id-attribute mode.
     */
    private Map fTagName2ElementInfoList;

    /**
     * The size of the document, in nodes.
     */
    private int fDocumentNodeSize;

    /**
     * Constructor.  Builds the table.
     */
    public ElementTable(MetaData metaData,
                        XMLCDocument xmlcDoc) throws XMLCException {
        fMetaData = metaData;
        fXmlcDoc = xmlcDoc;

        fGlobalIdAttrMode = (fXmlcDoc.getGlobalIdAttribute() != null);
        if (!fGlobalIdAttrMode) {
            fTagName2IdAttrName = new HashMap();
            fTagName2ElementInfoList = new HashMap();
        }
        fDocumentNodeSize = addElements(fXmlcDoc.getDocument());
    }

    /**
     * Recursively determine node sizes
     */
    private int getRecursiveNodeCount(Node node) {
        int count = getNodeCount(node);
        
        for (Node child = node.getFirstChild(); child != null;
             child = child.getNextSibling()) {
            count += getRecursiveNodeCount(child);
        }
        return count;
    }

    /**
     * Get the size of a single node (but not its children).  Does
     * include attribute sizes.
     */
    private int getNodeCount(Node node) {
        int count = 1;  // this node
        NamedNodeMap attrs = node.getAttributes();
        if (attrs != null) {
            int len = attrs.getLength();
            for (int idx = 0; idx < len; idx++) {
                count += getRecursiveNodeCount(attrs.item(idx));
            }
        }
        return count;
    }
    
    /**
     * Record information for local id-attribute mode.
     */
    private void recordLocalIdAttributeInfo(ElementInfo elementInfo,
                                            Element element) {
        String tagName = element.getTagName();

        fTagName2IdAttrName.put(tagName, fXmlcDoc.getIdAttrName(element));

        List idElementList = (List)fTagName2ElementInfoList.get(tagName);
        if (idElementList == null) {
            idElementList = new ArrayList();
            fTagName2ElementInfoList.put(tagName, idElementList);
        }
        idElementList.add(elementInfo);
    }

    /**
     * Add an element to the table.
     */
    private void addElement(Element element,
                            int nodeSize,
                            int subTreeSize) throws XMLCException {
        ElementInfo elementInfo
            = new ElementInfo(element, nodeSize, subTreeSize,
                              fMetaData, fXmlcDoc);

        // Check that Java id is unique
        String javaId = elementInfo.getJavaId();
        if (javaId != null) {
            //FIXME: Should build list and report at the end.
            if (fJavaIds.containsKey(javaId)) {
                throw new XMLCException("Duplicate element id \"" + elementInfo.getXmlId()
                                        + "\", id must be unique after first character is capitalized");
            }
            fJavaIds.put(javaId, elementInfo);
        }
        
        // Add to lists of all.
        fElements.put(element, elementInfo);

        // Handle id to element mapping
        if (elementInfo.hasInvalidJavaId()) {
            // Remember if this element has an invalid java id
            if (fInvalidElementIds == null) {
                fInvalidElementIds = new TreeMap();
            }
            fInvalidElementIds.put(elementInfo.getXmlId(),
                                   elementInfo);
        } else {
            // It has an id, add it to the index.
            String xmlId = elementInfo.getXmlId();
            if (xmlId != null) {
                fXmlIds.put(xmlId, elementInfo);
            }
        }

        if (!fGlobalIdAttrMode) {
            recordLocalIdAttributeInfo(elementInfo, element);
        }
    }

    /**
     * Recursively walk the DOM and enter all elements.
     * @return the size, in nodes, of the subtree starting at this
     *  element.
     */
    private int addElements(Node node) throws XMLCException {
        int nodeSize = getNodeCount(node);
        int childSize = 0;
        for (Node child = node.getFirstChild(); child != null;
             child = child.getNextSibling()) {
            childSize += addElements(child);
        }
        if (node instanceof Element) {
            addElement((Element)node, nodeSize, nodeSize+childSize);
        }
        return nodeSize+childSize;
    }

    /**
     * Get the XMLCDocument object stored in the table.
     */
    public XMLCDocument getXMLCDocument() {
        return fXmlcDoc;
    }

    /**
     * Get the size of the document, in nodes.
     */
    public int getDocumentNodeSize() {
        return fDocumentNodeSize;
    }
    
    /**
     * Is there only one attribute name for all id attributes?
     */
    public boolean isGlobalIdAttrMode() {
        return fGlobalIdAttrMode;
    }


    /**
     * Look up an ElementInfo by Element.
     */
    public ElementInfo getElementInfo(Element element) {
        ElementInfo info = (ElementInfo)fElements.get(element);
        if (info == null) {
            throw new XMLCError("element not found in element info table");
        }
        return info;
    }

    /**
     * Get a interator of all ElementInfo objects.
     */
    public Iterator getElements() {
        return fElements.values().iterator();
    }

    /**
     * Get an iterator of all ElementInfo objects that have Java ids.
     */
    public Iterator getJavaIdElements() {
        return fJavaIds.values().iterator();
    }

    /**
     * Get an iterator of ElementInfo entries by tag name.
     * Only valid in local-id-attribute mode.
     */
    public Iterator getElementsByTagName(String tagName) {
        return ((List)fTagName2ElementInfoList.get(tagName)).iterator();
    }

    /**
     * Get all tag names that were found in local-id-attribute mode.
     * Returns null in global-id-attribute mode.
     */
    public Iterator getTagNames() {
        if (fGlobalIdAttrMode) {
            return null;  // Not kept for global.
        } else {
            return fTagName2IdAttrName.keySet().iterator();
        }
    }

    /**
     * Get the id-attribute name for a tag.
     */
    public String getIdAttributeName(String tagName) {
        //FXIME: still needed??
        return (String)fTagName2IdAttrName.get(tagName);
    }

    /**
     * Get an sorted iterator of element ids that are not legal Java
     * identifiers, or null if all ids were legal.
     */
    public Iterator getInvalidElementIds() {
        if (fInvalidElementIds != null) {
            return fInvalidElementIds.keySet().iterator();
        } else {
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy