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

se.ugli.durian.j.dom.mutable.MutableElement Maven / Gradle / Ivy

package se.ugli.durian.j.dom.mutable;

import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static se.ugli.durian.j.dom.node.PrefixMapping.prefixMapping;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

import se.ugli.commons.Id;
import se.ugli.durian.j.dom.node.Attribute;
import se.ugli.durian.j.dom.node.Content;
import se.ugli.durian.j.dom.node.Element;
import se.ugli.durian.j.dom.node.ElementCloneApi;
import se.ugli.durian.j.dom.node.Node;
import se.ugli.durian.j.dom.node.NodeFactory;
import se.ugli.durian.j.dom.node.NodeListener;
import se.ugli.durian.j.dom.node.PrefixMapping;
import se.ugli.durian.j.dom.node.Text;
import se.ugli.durian.j.dom.serialize.Serializer;

public class MutableElement implements Element, MutableNode {

    private class SetParentListener implements NodeListener {

        @Override
        public void nodeAdded(final Node node) {
            ((MutableNode) node).setParent(MutableElement.this);
        }

        @Override
        public void nodeRemoved(final Node node) {
            ((MutableNode) node).setParent(null);
        }

    }

    private final Set attributes = new LinkedHashSet<>();
    private final List content = new ArrayList<>();
    private final List nodeListeners = new ArrayList<>();
    private final Map prefixByUri = new LinkedHashMap<>();

    private final String id = Id.create().value;
    private String name;
    private final NodeFactory nodeFactory;
    private Optional uri;

    private Optional parent = Optional.empty();

    public MutableElement(final String name, final String uri, final NodeFactory nodeFactory,
            final Iterable prefixMappings) {
        this.name = name;
        this.uri = Optional.ofNullable(uri);
        this.nodeFactory = nodeFactory;
        if (prefixMappings != null)
            for (final PrefixMapping prefixmapping : prefixMappings)
                prefixByUri.put(prefixmapping.uri, prefixmapping.prefix.orElse(null));
        nodeListeners.add(new SetParentListener());
    }

    public Node add(final Node node) {
        if (node != null) {
            if (node instanceof Content)
                content.add((Content) node);
            else if (node instanceof Attribute)
                attributes.add(node.as(Attribute.class));
            for (final NodeListener listener : nodeListeners)
                listener.nodeAdded(node);
        }
        return node;
    }

    public void addAll(final Collection nodes) {
        for (final Node node : nodes)
            add(node);
    }

    public Attribute addAttribute(final String name, final String value) {
        return addAttribute(name, uri.orElse(null), value, nodeFactory);
    }

    public Attribute addAttribute(final String name, final String uri, final String value,
            final NodeFactory nodeFactory) {
        final Attribute attribute = nodeFactory.createAttribute(name, uri, this, value);
        add(attribute);
        return attribute;
    }

    public Element addElement(final String name) {
        return addElement(name, uri.orElse(null), nodeFactory);
    }

    public Element addElement(final String name, final String uri, final NodeFactory nodeFactory,
            final PrefixMapping... prefixmappings) {
        final Element element = nodeFactory.createElement(name, uri, this, asList(prefixmappings));
        add(element);
        return element;
    }

    public void addListener(final NodeListener listener) {
        nodeListeners.add(listener);
    }

    public void addPrefixMapping(final String prefix, final String uri) {
        prefixByUri.put(uri, prefix);
    }

    public Text addText(final String value) {
        return addText(value, nodeFactory);
    }

    public Text addText(final String value, final NodeFactory nodeFactory) {
        final Text text = nodeFactory.createText(this, value);
        add(text);
        return text;
    }

    @Override
    public Optional attribute(final String attributeName) {
        for (final Attribute attribute : attributes)
            if (attribute.name().equals(attributeName))
                return Optional.of(attribute);
        return Optional.empty();
    }

    @Override
    public Stream attributes() {
        return new LinkedHashSet<>(attributes).stream();
    }

    @Override
    public Optional attributeValue(final String attributeName) {
        final Optional attribute = attribute(attributeName);
        if (attribute.isPresent())
            return Optional.ofNullable(attribute.get().value());
        return Optional.empty();
    }

    @Override
    public ElementCloneApi clone() {
        return new MutableElementCloneApiImpl(this);
    }

    @Override
    public Stream content() {
        return new ArrayList<>(content).stream();
    }

    @Override
    public Optional element(final String elementName) {
        return elements(elementName).findFirst();
    }

    @Override
    public Stream elements() {
        return new ArrayList<>(content).stream().filter(c -> c instanceof Element).map(c -> c.as(Element.class));
    }

    @Override
    public Stream elements(final String elementName) {
        return elements().filter(e -> e.name().equals(elementName));
    }

    @Override
    public Optional elementText(final String elementName) {
        final Optional element = element(elementName);
        if (element.isPresent() && element.get().hasTexts()) {
            final StringBuilder textBuilder = new StringBuilder();
            element.get().texts().forEach(text -> {
                textBuilder.append(text.value());
            });
            return Optional.of(textBuilder.toString());
        }
        return Optional.empty();
    }

    @Override
    public boolean hasAttributes() {
        return !attributes.isEmpty();
    }

    @Override
    public boolean hasElements() {
        for (final Content content : this.content)
            if (content instanceof Element)
                return true;
        return false;
    }

    @Override
    public boolean hasNodes() {
        return !attributes.isEmpty() && !content.isEmpty();
    }

    @Override
    public boolean hasTexts() {
        for (final Content content : this.content)
            if (content instanceof Text)
                return true;
        return false;
    }

    @Override
    public String id() {
        return id;
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public NodeFactory nodeFactory() {
        return nodeFactory;
    }

    @Override
    public Optional parent() {
        return parent;
    }

    @Override
    public String path() {
        final String selfPath = "/" + name;
        if (parent.isPresent())
            return parent.get().path() + selfPath;
        return selfPath;
    }

    @Override
    public String path(final String childPath) {
        if (childPath.startsWith("/"))
            return path() + childPath;
        return path() + "/" + childPath;
    }

    private Optional prefix(final String uri, final Element element) {
        for (final PrefixMapping prefixmapping : element.prefixMappings().collect(toList()))
            if (uri.equals(prefixmapping.uri))
                return prefixmapping.prefix;
        if (element.parent().isPresent())
            return prefix(uri, element.parent().get());
        return Optional.empty();
    }

    @Override
    public Stream prefixMappings() {
        final List prefixmappings = new ArrayList<>();
        for (final Entry entry : prefixByUri.entrySet())
            prefixmappings.add(prefixMapping(entry.getValue(), entry.getKey()));
        return prefixmappings.stream();
    }

    @Override
    public String qName() {
        return uri.flatMap(u -> prefix(u, this)).map(p -> p + ":" + name).orElse(name);
    }

    @Override
    public String relativePath(final String childPath) {
        if (childPath.startsWith("/"))
            return name + childPath;
        return name + "/" + childPath;
    }

    public boolean remove(final Node node) {
        boolean result = false;
        if (node != null) {
            if (node instanceof Content)
                result = content.remove(node);
            if (node instanceof Attribute)
                result = attributes.remove(node);
            for (final NodeListener listener : nodeListeners)
                listener.nodeAdded(node);
        }
        return result;
    }

    public int removeAll(final Class type) {
        final AtomicInteger result = new AtomicInteger(0);
        if (Attribute.class.isAssignableFrom(type))
            attributes().forEach(attribute -> {
                if (type.isInstance(attribute))
                    if (remove(attribute))
                        result.incrementAndGet();
            });
        if (Content.class.isAssignableFrom(type))
            content().forEach(content -> {
                if (type.isInstance(content))
                    if (remove(content))
                        result.incrementAndGet();
            });
        return result.get();
    }

    public int removeAll(final Stream nodes) {
        final AtomicInteger result = new AtomicInteger(0);
        nodes.forEach(node -> {
            if (remove(node))
                result.incrementAndGet();
        });
        return result.get();
    }

    public boolean removeElement(final String elementName) {
        final Optional element = element(elementName);
        if (element.isPresent())
            return remove(element.get());
        return false;
    }

    public int removeElements(final String elementName) {
        return removeAll(elements(elementName));
    }

    public void removeListener(final NodeListener listener) {
        nodeListeners.add(listener);
    }

    @Override
    public MutableQueryApi select() {
        return new MutableQueryApiImpl(this);
    }

    public void setAttributeValue(final String attributeName, final String value) {
        final Optional attributeOpt = attribute(attributeName).map(a -> a.as(MutableAttribute.class));
        if (attributeOpt.isPresent()) {
            final MutableAttribute attribute = attributeOpt.get();
            if (value == null)
                remove(attribute);
            else
                attribute.setValue(value);
        }
        else if (value != null)
            add(nodeFactory.createAttribute(attributeName, uri.orElse(null), this, value));
    }

    public void setElement(final String elementName, final Element element) {
        if (element != null && !element.name().equals(elementName))
            throw new IllegalStateException(elementName + "!=" + element.name());
        removeElement(elementName);
        if (element != null)
            add(element);
    }

    public void setName(final String name) {
        this.name = name;
    }

    @Override
    public void setParent(final Element parent) {
        this.parent = Optional.ofNullable(parent);
    }

    public void setText(final String text) {
        removeAll(Text.class);
        addText(text);
    }

    public void setUri(final String uri) {
        this.uri = Optional.ofNullable(uri);
    }

    @Override
    public Stream texts() {
        return new ArrayList<>(content).stream().filter(c -> c instanceof Text).map(c -> c.as(Text.class));
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "[name=" + name + ", uri=" + uri + "]";
    }

    @Override
    public String toXml() {
        return Serializer.serialize(this);
    }

    @Override
    public Optional uri() {
        return uri;
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj instanceof Element)
            return id.equals(((Element) obj).id());
        return false;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy