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

com.codename1.xml.Element Maven / Gradle / Ivy

There is a newer version: 7.0.161
Show newest version
/*
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores
 * CA 94065 USA or visit www.oracle.com if you need additional information or
 * have any questions.
 */
package com.codename1.xml;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

/**
 * The Element class defines a single XML element with its attributes and children.
 * Due to its hierarchial nature, this class can be used for a single "leaf" Element, for more complex elements (with child elements), and up to describing the entire document.
 *
 * @author Ofir Leitner
 */
public class Element implements Iterable {

    /**
     * A constant that can be used for the get descendants methods to denote infinite recursion
     */
    public static final int DEPTH_INFINITE = Integer.MAX_VALUE;

    /**
     * True if this is a text element, false otherwise
     */
    private boolean textElement;

    /**
     * The element's name (or text for text elements)
     */
    private String name;

   /**
     * A vector containing this element's children
     */
    private ArrayList children;

    /**
     * This element's parent
     */
    private Element parent;

    /**
     * A hashtable containing this element's attributes
     */
    private Hashtable attributes;

    boolean isComment;

    boolean caseSensitive;
    
    /**
     * Constructs and Element without specifying a name
     * This can be used by subclasses that do not require name assigments.
     */
    protected Element() {
    }


    /**
     * Constructs an Element with the specified name
     * 
     * @param tagName The tag name
     */
    public Element(String tagName) {
        this.name=tagName;
    }

    /**
     * Constructs an Element (or a text element) with the specified name or text.
     *
     * @param tagName The tag name, or in the case of a text element the element's text
     * @param isTextElement true for a text element, false otherwise
     */
    public Element(String tagName,boolean isTextElement) {
        this(tagName);
        textElement=isTextElement;
    }


    /**
     * Returns true if this is a text element, false otherwise
     * 
     * @return true if this is a text element, false otherwise
     */
    public boolean isTextElement() {
        return textElement;
    }

    /**
     * Returns this Element's tag name
     *
     * @return the Element's tag name
     * @throws IllegalStateException if this is a text element
     */
    public String getTagName() {
        if (textElement) {
                throw new IllegalStateException("Text elements do not have a tag name");
        }
        return name;
    }

    /**
     * Returns the attributes Hashtable
     *
     * @return the attributes Hashtable
     */
    public Hashtable getAttributes() {
        return attributes;
    }

    /**
     * Adds the specified attribute and value to this Element if it is supported for the Element and has a valid value.
     * This method allows creating a key that is non-string to be used by subclasses that optimize attributes retrieval
     * 
     * @param id The attribute ID
     * @param value The attribute value
     */
    protected void setAttribute(Object id,String value) {
        if (attributes==null) {
            attributes=new Hashtable();
        }
        attributes.put(id,value);
    }

    /**
     * Adds the specified Element as a child to this element.
     * If the specified element was found to be unsupported (i.e. it's ID is TAG_UNSUPPORTED, it is not added.
     *
     * @param childElement The child element
     */
    public void addChild(Element childElement) {
        setChildParent(childElement);
        children.add(childElement);
        //childElement.setParent(this);
    }

    /**
     * Sets this element parent, done interanlly in addChild
     *
     * @param parent The element's parent
     */
    protected void setParent(Element parent) {
        this.parent=parent;
    }

    /**
     * Returns this Element's parent
     *
     * @return this Element's parent
     */
    public Element getParent() {
        return parent;
    }


    /**
     Returns the number of this Element's children
     *
     * @return the number of this Element's children
     */
    public int getNumChildren() {
        if (children==null) {
            return 0;
        }
        return children.size();
    }

    /**
     * Returns the internal children vector
     *
     * @return the children vector
     * @deprecated this uses the old vector API instead of the more modern Collection/List
     */
    protected Vector getChildren() {
        if(children == null) {
            return null;
        }
        return new Vector(children);
    }

    /**
     * Sets the children vector of this Element
     *
     * @param children The vector to set as this Element's children
     * @deprecated this uses the old vector API instead of the more modern Collection/List
     */
    protected void setChildren(Vector children) {
        if(children == null) {
            this.children = null;
        } else {
            this.children = new ArrayList(children);
        }
    }

    /**
     * Sets the name or text (for text elements) of this tag
     *
     * @param name The name or text of this tag
     */
    protected void setTagName(String name) {
        this.name=name;
    }

    /**
     * Sets this element as a text element 
     * 
     * @param textElement true to set this as a text element, false otherwise
     */
    protected void setTextElement(boolean textElement) {
        this.textElement = textElement;
    }





    /**
     * Returns the Element's child positioned at the specified index
     *
     * @param index The requested index
     * @return child number index of this ELement
     * @throws ArrayIndexOutOfBoundsException if the index is bigger than the children's count or smaller than 0
     */
    public Element getChildAt(int index) {
        if ((index<0) || (children==null) || (index>=children.size())) {
            throw new ArrayIndexOutOfBoundsException();
        }
        return (Element)children.get(index);

    }

    /**
     * Compares a name to a tag. Returns true if the tag has that name, or if tagName = '*'.
     * @param tagName The tag name to compare, or '*' to match any tag.
     * @param tag The element whose tag we are comparing.
     * @return True if tagName='*' or if the tagName matches the tag name of tag.
     */
    private static boolean cmpTagName(String tagName, Element tag) {
        if ("*".equals(tagName)) {
            return true;
        }
        return tagName.equalsIgnoreCase(tag.getTagName());
    }
    
    /**
     * Returns an Element's child by a tag name
     *
     * @param name The child's tag name
     * @return the first child with the specified name, or null if not found
     */
    public Element getFirstChildByTagName(String name) {
        if (children==null) {
            return null;
        }
        int i=0;
        Element found=null;
        while ((found==null) && (i1) {
                    child.getDescendantsByTagNameInternal(v, name,depth-1);
                }
                if ((!child.textElement) && cmpTagName(name, child)) {
                    v.addElement(child);
                }
                i++;
            }
        }

    }

    private void getDescendantsByTagNameAndAttributeInternal(Vector v,String name,String attribute, int depth) {
        if (children!=null) {
            int i=0;
            while (i1) {
                    child.getDescendantsByTagNameAndAttributeInternal(v, name, attribute, depth-1);
                }
                if ((!child.textElement) && cmpTagName(name, child)) {
                    String a = child.getAttribute(attribute);
                    if(a != null && a.length() > 0) {
                        v.addElement(child);
                    }
                }
                i++;
            }
        }

    }

    /**
     *  Returns all descendants with the specified tag name and the none empty attribute
     * 
     * @param name The tag name to look for
     * @param attributeName the attribute that must exist on the tag
     * @param depth The search depth (1 - children, 2 - grandchildren .... DEPTH_INFINITE - for all descendants)
     *
     * @return A vector containing descendants with the specified tag name
     */
    public Vector getDescendantsByTagNameAndAttribute(String name, String attributeName, int depth) {
        if (depth<1) {
            throw new IllegalArgumentException("Depth must be 1 or higher");
        }
        if (children==null) {
            return new Vector();
        }
        Vector v=new Vector();
        getDescendantsByTagNameAndAttributeInternal(v, name, attributeName, depth);
        return v;
    }
    
    /**
     *  Returns all descendants with the specified tag name
     * 
     * @param name The tag name to look for
     * @param depth The search depth (1 - children, 2 - grandchildren .... DEPTH_INFINITE - for all descendants)
     *
     * @return A vector containing descendants with the specified tag name
     */
    public Vector getDescendantsByTagName(String name,int depth) {
        if (depth<1) {
            throw new IllegalArgumentException("Depth must be 1 or higher");
        }
        
        Vector v=new Vector();
        if(children != null) {
            getDescendantsByTagNameInternal(v, name, depth);
        }
        return v;
    }

    /**
     *  Returns all descendants with the specified tag name
     *
     * @param name The tag name to look for
     * @return A vector containing descendants with the specified tag name
     */
    public Vector getDescendantsByTagName(String name) {
        return getDescendantsByTagName(name, DEPTH_INFINITE);
    }


    /**
     * Returns all children with the specified tag name
     * 
     * @param name The tag name to look for
     * @return A vector containing children with the specified tag name
     */
    public Vector getChildrenByTagName(String name) {
        return getDescendantsByTagName(name, 1);
    }

    private void getTextDescendantsInternal(Vector v,String text,boolean caseSensitive,int depth) {
        if (children==null) {
            return;
        }
        int i=0;
        while (i0) {
                child.getTextDescendantsInternal(v, text, caseSensitive, depth-1);
            }
            if (child.textElement) {
                if (text!=null) {
                    String childText=child.getText();
                    if (!caseSensitive) {
                        childText=childText.toLowerCase();
                    }
                    int index=childText.indexOf(text);
                    if (index!=-1) {
                        v.addElement(child);
                    }
                } else { // if text==null, it means we want all text children
                    v.addElement(child);
                }
            }
             i++;
        }
    }


    /**
     *  Returns all text descendants containing the specified text
     *
     * @param text The text to look for (null to return all text children)
     * @param caseSensitive true to perform a case sensitive match, false to ignore case
     * @param depth The search depth (1 - children, 2 - grandchildren .... DEPTH_INFINITE - for all descendants)
     * @return A vector containing descendants containing the specified text
     */
    public Vector getTextDescendants(String text,boolean caseSensitive,int depth) {
        if (depth<1) {
            throw new IllegalArgumentException("Depth must be 1 or higher");
        }
        if (children==null) {
            return new Vector();
        }
        if ((!caseSensitive) && (text!=null)) {
            text=text.toLowerCase();
        }
        Vector v=new Vector();
        getTextDescendantsInternal(v,text,caseSensitive,depth);
        return v;
    }

    /**
     *  Returns all text descendants containing the specified text
     *
     * @param text The text to look for (null to return all text children)
     * @param caseSensitive true to perform a case sensitive match, false to ignore case
     * @return A vector containing decensants containing the specified text
     */
    public Vector getTextDescendants(String text,boolean caseSensitive) {
        return getTextDescendants(text, caseSensitive, DEPTH_INFINITE);
    }

    /**
     * Returns all children with the specified text
     *
     * @param text The text to look for (null to return all text children)
     * @param caseSensitive true to perform a case sensitive match, false to ignore case
     * @return A vector containing children containing the specified text
     */
    public Vector getTextChildren(String text,boolean caseSensitive) {
        return getTextDescendants(text, caseSensitive, 1);
    }

    /**
     * Returns true if the specified element is contained in this element's hierarchy (meaning it is one of its descendants)
     * 
     * @param element The element to look for
     * @return true if this element contains the specified element, false otherwise
     */
    public boolean contains(Element element) {
        if (this==element) {
            return true;
        }
        if (children!=null) {
            int i=0;
            while (i();
        }
        child.setParent(this);
    }

    /**
     * Removes the child at the given index
     * 
     * @param index The child's index
     */
    public void removeChildAt(int index) {
        if ((index<0) || (children==null) || (index>=children.size())) {
            throw new ArrayIndexOutOfBoundsException();
        }
        Element child=(Element)children.get(index);
        child.setParent(null);
        children.remove(index);
    }

    /**
     * Returns the child index
     *  
     * @param child The child element to look for
     * @return The child position, or -1 if the child does not belong to this element.
     */
    public int getChildIndex(Element child) {
        int result=-1;
        if (children!=null) {
            for(int i=0;i\n";
        } else {
            str+="'"+name+"'\n";
        }
        return str;
   }

    /**
     * Determines whether or not this Element has any text children.
     * @return true if any of this Elements children are text Elements.
     */
    public boolean hasTextChild() {
        if(children != null) {
            for (int iter = 0 ; iter < children.size() ; iter++) {
                Object child = children.get(iter);
                if (child instanceof Element && ((Element)child).isTextElement()) {
                    return true;
                }
            }
        }
        return false;
    }
   
    /**
     * Determines whether or not this Element has no children.
     * @return true if this Element has no children.
     */
    public boolean isEmpty() {
        return children == null || children.isEmpty();
    }

    /**
     * Iterable for children of this entry making tree walking easier, this makes for(Element child : base) {} possible
     * @return the children iterator
     */
    public Iterator iterator() {
        return children.iterator();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy