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

com.reandroid.xml.XMLElement Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright (C) 2022 github.com/REAndroid
 *
 *  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 com.reandroid.xml;

import com.reandroid.common.Namespace;
import com.reandroid.utils.collection.ArrayCollection;
import com.reandroid.utils.collection.CollectionUtil;
import com.reandroid.utils.collection.IndexIterator;
import com.reandroid.utils.collection.SizedSupplier;
import com.reandroid.xml.base.Attribute;
import com.reandroid.xml.base.Element;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.function.Predicate;

public class XMLElement extends XMLNodeTree implements Element {

    private ArrayCollection mAttributes;
    private String mName;
    private XMLNamespace mNamespace;
    private ArrayCollection mNamespaceList;

    public XMLElement(){
        super();
        mAttributes = EMPTY_ATTRIBUTES;
        mNamespaceList = EMPTY_NAMESPACES;
    }
    public XMLElement(String tagName){
        this();
        setName(tagName);
    }
    @Override
    XMLElement newCopy(XMLNode parent){
        XMLElement element = newElement();
        if(parent instanceof XMLNodeTree){
            ((XMLNodeTree)parent).add(element);
        }
        int count = getNamespaceCount();
        for(int i = 0; i < count; i++){
            getNamespaceAt(i).newCopy(element);
        }
        setName(getUri(), getPrefix(), getName(false));
        count = getAttributeCount();
        for(int i = 0; i < count; i++){
            element.addAttribute(getAttributeAt(i).newCopy(element));
        }
        Iterator iterator = iterator();
        while(iterator.hasNext()){
            iterator.next().newCopy(element);
        }
        return element;
    }
    public void addText(String text){
        XMLText xmlText = newText();
        xmlText.setText(text);
        add(xmlText);
    }
    public XMLAttribute getAttributeAt(int index){
        return mAttributes.get(index);
    }
    public Iterator getAttributes() {
        return new IndexIterator<>(new SizedSupplier() {
            @Override
            public int size() {
                return getAttributeCount();
            }
            @Override
            public XMLAttribute get(int index) {
                return getAttributeAt(index);
            }
        });
    }
    public String getUri(){
        XMLNamespace namespace = getNamespace();
        if(namespace != null){
            return namespace.getUri();
        }
        return null;
    }
    public String getPrefix(){
        XMLNamespace namespace = getNamespace();
        if(namespace != null){
            return namespace.getPrefix();
        }
        return null;
    }
    public XMLNamespace getNamespace(){
        return mNamespace;
    }
    public void setNamespace(XMLNamespace namespace) {
        this.mNamespace = namespace;
    }
    public void setNamespace(Namespace namespace) {
        if(namespace == null){
            setNamespace(null, null);
        }else {
            setNamespace(namespace.getUri(), namespace.getPrefix());
        }
    }
    public void setNamespace(String uri, String prefix) {
        setNamespace(getOrCreateXMLNamespace(uri, prefix));
    }

    public int getNamespaceCount(){
        return mNamespaceList.size();
    }
    public XMLNamespace getNamespaceAt(int index){
        return mNamespaceList.get(index);
    }

    @Override
    public Iterator getNamespaces() {
        return mNamespaceList.iterator();
    }

    @Override
    public XMLNamespace newNamespace(String uri, String prefix) {
        return new XMLNamespace(uri, prefix);
    }
    @Override
    public XMLAttribute newAttribute() {
        return new XMLAttribute();
    }
    @Override
    public XMLElement newElement() {
        return new XMLElement();
    }
    @Override
    public XMLText newText() {
        return super.newText();
    }

    public void addNamespace(String uri, String prefix){
        if(uri == null || prefix == null){
            return;
        }
        addNamespace(newNamespace(uri, prefix));
    }
    public void addNamespace(XMLNamespace namespace){
        if(namespace != null && !mNamespaceList.contains(namespace)){
            if(mNamespaceList == EMPTY_NAMESPACES){
                mNamespaceList = new ArrayCollection<>();
            }else if(mNamespaceList.contains(namespace)){
                return;
            }
            mNamespaceList.add(namespace);
        }
    }
    public XMLNamespace getOrCreateXMLNamespace(String uri, String prefix){
        if(uri == null || prefix == null){
            return null;
        }
        XMLNamespace namespace = getXMLNamespace(uri, prefix);
        if(namespace != null){
            return namespace;
        }
        namespace = newNamespace(uri, prefix);
        getRootElement().addNamespace(namespace);
        return namespace;
    }
    public XMLNamespace getXMLNamespace(String uri, String prefix){
        if(uri == null || prefix == null){
            return null;
        }
        int count = getNamespaceCount();
        for(int i = 0; i < count; i++){
            XMLNamespace namespace = getNamespaceAt(i);
            if(namespace.isEqual(uri, prefix)){
                return namespace;
            }
        }
        XMLElement parent = getParentElement();
        if(parent != null){
            return parent.getXMLNamespace(uri, prefix);
        }
        return null;
    }
    public XMLNamespace getXMLNamespaceByUri(String uri){
        if(uri == null){
            return null;
        }
        int count = getNamespaceCount();
        for(int i = 0; i < count; i++){
            XMLNamespace namespace = getNamespaceAt(i);
            if(uri.equals(namespace.getUri())){
                return namespace;
            }
        }
        XMLElement parent = getParentElement();
        if(parent != null){
            return parent.getXMLNamespaceByUri(uri);
        }
        return null;
    }
    public XMLNamespace getXMLNamespaceByPrefix(String prefix){
        if(prefix == null){
            return null;
        }
        int count = getNamespaceCount();
        for(int i = 0; i < count; i++){
            XMLNamespace namespace = getNamespaceAt(i);
            if(prefix.equals(namespace.getPrefix())){
                return namespace;
            }
        }
        XMLElement parent = getParentElement();
        if(parent != null){
            return parent.getXMLNamespaceByPrefix(prefix);
        }
        return null;
    }
    public Collection listAttributes(){
        return mAttributes;
    }
    public int getChildElementsCount(){
        return super.countNodesWithType(XMLElement.class);
    }
    public List getChildElementList(){
        return CollectionUtil.toList(iterator(XMLElement.class));
    }
    public XMLElement getElement(String name){
        return CollectionUtil.getFirst(getElements(name));
    }
    public Iterator getElements(){
        return iterator(XMLElement.class);
    }
    public Iterator getElements(Predicate filter){
        return iterator(XMLElement.class, filter);
    }
    public Iterator getElements(String name){
        return getElements(element -> element.equalsName(name));
    }
    public int getAttributeCount(){
        return mAttributes.size();
    }
    public String getAttributeValue(String name){
        XMLAttribute attribute = getAttribute(name);
        if(attribute != null){
            return attribute.getValueAsString();
        }
        return null;
    }
    public XMLAttribute getAttribute(String name){
        if(name == null){
            return null;
        }
        int count = getAttributeCount();
        for(int i = 0; i < count; i++){
            XMLAttribute attribute = getAttributeAt(i);
            if (attribute.equalsName(name)){
                return attribute;
            }
        }
        return null;
    }
    public void clearAttributes(){
        if(mAttributes.size() == 0){
            return;
        }
        for(int i = 0; i < mAttributes.size(); i++){
            XMLAttribute attribute = mAttributes.get(i);
            attribute.setParentNode(null);
        }
        mAttributes.clear();
        mAttributes.trimToSize();
    }
    public XMLAttribute removeAttribute(String name){
        XMLAttribute attribute = getAttribute(name);
        if(attribute != null){
            attribute.setParentNode(null);
        }
        return attribute;
    }
    public XMLAttribute removeAttribute(XMLAttribute attribute){
        if( mAttributes.remove(attribute) && attribute != null){
            attribute.setParentNode(null);
        }
        return attribute;
    }
    public XMLAttribute removeAttributeAt(int index){
        XMLAttribute attribute = mAttributes.remove(index);
        if(attribute != null){
            attribute.setParentNode(null);
        }
        return attribute;
    }
    public XMLAttribute setAttribute(String name, String value){
        if(XMLUtil.isEmpty(name)){
            return null;
        }
        XMLAttribute xmlAttribute = getAttribute(name);
        if(xmlAttribute == null){
            if(XMLNamespace.looksNamespace(name, value)){
                XMLNamespace namespace = newNamespace(value, XMLUtil.splitName(name));
                addNamespace(namespace);
            }else{
                addAttribute(newAttribute().set(name,value));
            }
        }else {
            xmlAttribute.setValue(value);
        }
        return xmlAttribute;
    }
    public void addAttribute(String name, String value){
        if(XMLUtil.isEmpty(name)){
            return;
        }
        if(XMLNamespace.looksNamespace(name, value)){
            XMLNamespace namespace = newNamespace(value, XMLUtil.splitName(name));
            addNamespace(namespace);
        }else{
            addAttribute(newAttribute().set(name,value));
        }
    }
    public void addAttribute(String uri, String prefix, String name, String value){
        if(XMLUtil.isEmpty(name)){
            return;
        }
        if(XMLNamespace.looksNamespace(name, value)){
            XMLNamespace namespace = newNamespace(value, XMLUtil.splitName(name));
            addNamespace(namespace);
        }else{
            XMLAttribute attribute = new XMLAttribute();
            addAttribute(attribute);
            attribute.setName(uri, prefix, name);
            attribute.setValue(value);
        }
    }
    public void addAttribute(Attribute attribute){
        if(attribute == null){
            return;
        }
        XMLAttribute xmlAttribute = (XMLAttribute) attribute;
        if(mAttributes == EMPTY_ATTRIBUTES){
            mAttributes = new ArrayCollection<>();
        }
        mAttributes.add(xmlAttribute);
        xmlAttribute.setParentNode(this);
    }
    public void addAttribute(int i, Attribute attribute){
        if(attribute == null){
            return;
        }
        XMLAttribute xmlAttribute = (XMLAttribute) attribute;
        if(mAttributes == EMPTY_ATTRIBUTES){
            mAttributes = new ArrayCollection<>();
        }
        mAttributes.add(i, xmlAttribute);
        xmlAttribute.setParentNode(this);
    }
    public XMLElement getParentElement(){
        XMLNode parent = getParentNode();
        if(parent instanceof XMLElement){
            return (XMLElement) parent;
        }
        return null;
    }
    public XMLElement getRootElement(){
        XMLElement parent = getParentElement();
        if(parent != null){
            return parent.getRootElement();
        }
        return this;
    }
    public XMLDocument getParentDocument(){
        XMLElement root = getRootElement();
        XMLNode parent = root.getParentNode();
        if(parent instanceof XMLDocument){
            return (XMLDocument) parent;
        }
        return null;
    }
    public int getDepth(){
        int result = 1;
        XMLElement parent = getParentElement();
        while (parent != null){
            result ++;
            parent = parent.getParentElement();
        }
        return result;
    }
    public boolean equalsName(String name){
        if(name == null){
            return getName() == null;
        }
        String prefix = XMLUtil.splitPrefix(name);
        if(prefix != null && !prefix.equals(getPrefix())){
            return false;
        }
        return name.equals(getName());
    }
    public String getName(){
        return mName;
    }
    public String getName(boolean includePrefix){
        String name = getName();
        if(!includePrefix){
            return name;
        }
        String prefix = getPrefix();
        if(prefix != null){
            name = prefix + ":" + name;
        }
        return name;
    }
    public void setName(String name){
        setName(null, null, name);
    }
    public void setName(String uri, String name){
        setName(uri, null, name);
    }
    public void setName(String uri, String prefix, String name){
        mName = XMLUtil.splitName(name);
        if(prefix == null){
            prefix = XMLUtil.splitPrefix(name);
        }
        if(XMLUtil.isEmpty(uri)){
            uri = null;
        }
        if(uri == null && prefix == null){
            return;
        }
        XMLNamespace namespace;
        if(uri == null){
            namespace = getXMLNamespaceByPrefix(prefix);
            if(namespace == null){
                throw new IllegalArgumentException("Namespace not found for prefix: " + prefix);
            }
        }else {
            namespace = getXMLNamespaceByUri(uri);
            if(namespace == null){
                throw new IllegalArgumentException("Namespace not found for uri: " + uri);
            }
        }
        setNamespace(namespace);
    }
    public String getTextContent(){
        return getTextContent(false);
    }
    public String getTextContent(boolean escapeXmlText){
        StringWriter writer = new StringWriter();
        try {
            Iterator iterator = iterator();
            while (iterator.hasNext()){
                XMLNode child = iterator.next();
                child.write(writer, true, escapeXmlText);
            }
            writer.flush();
            writer.close();
        }catch (IOException ignored){
        }
        return writer.toString();
    }
    public boolean hasChildElements(){
        return !CollectionUtil.isEmpty(getElements());
    }
    public boolean hasTextNode() {
        return !CollectionUtil.isEmpty(iterator(XMLText.class));
    }
    public boolean hasAttribute(String name) {
        return getAttribute(name) != null;
    }
    public void setTextContent(String text, boolean escape){
        super.clear();
        if(escape){
            text = XMLUtil.escapeXmlChars(text);
        }
        addText(text);
    }
    @Override
    void startSerialize(XmlSerializer serializer) throws IOException {
        int count = getNamespaceCount();
        for(int i = 0; i < count; i++){
            XMLNamespace namespace = getNamespaceAt(i);
            serializer.setPrefix(namespace.getPrefix(),
                    namespace.getUri());
        }
        serializer.startTag(getUri(), getName(false));
        count = getAttributeCount();
        for(int i = 0; i < count; i++){
            getAttributeAt(i).serialize(serializer);
        }
    }
    @Override
    void endSerialize(XmlSerializer serializer) throws IOException {
        serializer.endTag(getUri(), getName(false));
    }

    @Override
    public void parse(XmlPullParser parser) throws XmlPullParserException, IOException {
        int event = parser.getEventType();
        if(event != XmlPullParser.START_TAG){
            throw new XmlPullParserException("Not START_TAG event");
        }
        parseNamespaces(parser);
        setName(parser.getNamespace(), parser.getPrefix(), parser.getName());
        parseAttributes(parser);
        event = parser.next();
        XMLText xmlText = null;
        while (event != XmlPullParser.END_TAG && event != XmlPullParser.END_DOCUMENT){
            if(event == XmlPullParser.START_TAG){
                XMLElement element = newElement();
                add(element);
                element.parse(parser);
                xmlText = null;
            }else if(XMLText.isTextEvent(event)){
                if(xmlText == null){
                    xmlText = newText();
                }
                xmlText.parse(parser);
                if(!xmlText.isIndent()){
                    add(xmlText);
                }
            }else if(event == XmlPullParser.COMMENT){
                XMLComment comment = newComment();
                if(comment != null){
                    add(comment);
                    comment.parse(parser);
                }else {
                    parser.next();
                }
                xmlText = null;
            }else {
                xmlText = null;
                parser.next();
            }
            event = parser.getEventType();
        }
        if(parser.getEventType() == XmlPullParser.END_TAG){
            parser.next();
        }
    }
    private void parseNamespaces(XmlPullParser parser) throws XmlPullParserException {
        int count = parser.getNamespaceCount(getDepth());
        for(int i = 0; i < count; i++){
            addNamespace(parser.getNamespaceUri(i),
                    parser.getNamespacePrefix(i));
        }
        count = parser.getAttributeCount();
        for(int i = 0; i < count; i++){
            String name = parser.getAttributeName(i);
            String value = parser.getAttributeValue(i);
            if(XMLNamespace.looksNamespace(name, value)){
                addNamespace(value, XMLUtil.splitName(name));
            }
        }
    }
    public void parseAttributes(XmlPullParser parser){
        boolean processNamespaces = parser.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
        int count = parser.getAttributeCount();
        for(int i = 0; i < count; i++){
            String name = parser.getAttributeName(i);
            String value = parser.getAttributeValue(i);
            if(!XMLNamespace.looksNamespace(name, value)){
                String uri = parser.getAttributeNamespace(i);
                String prefix = parser.getAttributePrefix(i);
                if(processNamespaces) {
                    name = XMLUtil.splitName(name);
                }
                addAttribute(uri, prefix, name, value);
            }
        }
    }
    @Override
    void write(Appendable appendable, boolean xml, boolean escapeXmlText) throws IOException {
        appendable.append('<');
        appendable.append(getName());
        appendAttributes(appendable, xml, escapeXmlText);
        boolean haveChildes = false;
        Iterator iterator = iterator();
        while (iterator.hasNext()){
            if(!haveChildes){
                appendable.append(">");
            }
            XMLNode child = iterator.next();
            child.write(appendable, xml, escapeXmlText);
            haveChildes = true;
        }
        if(haveChildes){
            appendable.append("');
        }else {
            appendable.append("/>");
        }
    }
    void appendAttributes(Appendable appendable, boolean xml, boolean escapeXmlText) throws IOException {
        char separator;
        if(xml){
            separator = ' ';
        }else {
            separator = ';';
        }
        Iterator iterator = getAttributes();
        while (iterator.hasNext()){
            appendable.append(separator);
            iterator.next().write(appendable, xml, escapeXmlText);
        }
    }

    @Override
    int appendDebugText(Appendable appendable, int limit, int length) throws IOException {
        if(length >= limit){
            return length;
        }
        appendable.append('<');
        length ++;
        String name = getName(true);
        if(name == null){
            name = "null";
        }
        appendable.append(name);
        length += name.length();
        Iterator attributes = getAttributes();
        while (attributes.hasNext() && length < limit){
            appendable.append(' ');
            length ++;
            length = attributes.next()
                    .appendDebugText(appendable, limit, length);
        }
        boolean hasChildes = false;
        Iterator iterator = iterator();
        while (iterator.hasNext() && length < limit){
            if(!hasChildes){
                appendable.append("/>");
                length += 2;
            }
            length = iterator.next().appendDebugText(appendable, limit, length);
            hasChildes = true;
        }
        if(hasChildes){
            appendable.append("');
            length += 3;
        }else {
            appendable.append("/>");
            length += 2;
        }
        return length;
    }
    public static XMLElement parseElement(XmlPullParser parser) throws IOException, XmlPullParserException {
        XMLElement element = new XMLElement();
        element.parse(parser);
        return element;
    }

    private static final ArrayCollection EMPTY_ATTRIBUTES = ArrayCollection.empty();
    private static final ArrayCollection EMPTY_NAMESPACES = ArrayCollection.empty();
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy