blob: a7506ade1d695a8e35fe825b9abed92eced8d098 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.axiom.om;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.axiom.om.util.StAXParserConfiguration;
import org.apache.axiom.om.xpath.AXIOMXPath;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Iterator;
/**
* A particular kind of node that represents an element infoset information item.
* <p>
* An element has a collection of children, attributes, and namespace declarations. In contrast with
* DOM, this interface exposes namespace declarations separately from the attributes.
* <p>
* Namespace declarations are either added explicitly using
* {@link #declareNamespace(String, String)}, {@link #declareDefaultNamespace(String)} or
* {@link #declareNamespace(OMNamespace)}, or are created implicitly as side effect of other method
* calls:
* <ul>
* <li>If the element is created with a namespace and no matching namespace declaration is in scope
* in the location in the tree where the element is created, then an appropriate namespace
* declaration will be automatically added to the newly created element. The exact rules depend on
* the method chosen to create the element; see for example {@link OMFactory#createOMElement(QName)}.
* <li>If an attribute with a namespace is added, but no matching namespace declaration is in scope
* in the element, one is automatically added. See {@link #addAttribute(OMAttribute)} for more
* details.
* </ul>
* Thus, creating a new element or adding an attribute preserves the consistency of the object model
* with respect to namespaces. However, Axiom does not enforce namespace well-formedness for all
* possible operations on the object model. E.g. moving an element from one location in the tree to
* another one may cause the object model to loose its namespace well-formedness. In that case it is
* possible that the object model contains elements or attributes with namespaces for which no
* corresponding namespace declarations are in scope.
* <p>
* Fortunately, loosing namespace well-formedness has only very limited impact:
* <ul>
* <li>If namespace well-formedness is lost, the string to {@link QName} resolution for attribute
* values and element content may be inconsistent, i.e. {@link #resolveQName(String)},
* {@link #getTextAsQName()} and {@link OMText#getTextAsQName()} may return incorrect results.
* However, it should be noted that these methods are most relevant for object model instances that
* have been loaded from existing documents or messages. These object models are guaranteed to be
* well-formed with respect to namespaces (unless they have been modified after loading).
* <li>During serialization, Axiom will automatically repair any namespace inconsistencies. It will
* add necessary namespace declarations to the output document where they are missing in the object
* model and generate modified namespace declarations where the original ones in the object model
* are inconsistent. It will also omit redundant namespace declarations. Axiom guarantees that in
* the output document, every element and attribute (and {@link OMText} instance with a
* {@link QName} value) will have the same namespace URI as in the object model, thus preserving the
* intended semantics of the document. On the other hand, the namespace prefixes used in the output
* document may differ from the ones in the object model.
* <li>More precisely, Axiom will always make sure that any {@link OMElement} or {@link OMAttribute}
* node will keep the namespace URI that has been assigned to the node at creation time, unless the
* namespace is explicitly changed using {@link #setNamespace(OMNamespace)} or
* {@link OMNamedInformationItem#setNamespace(OMNamespace, boolean)}.
* </ul>
*/
public interface OMElement extends OMNode, OMContainer, OMNamedInformationItem {
/**
* Returns a filtered list of children - just the elements.
*
* @return Returns an iterator over the child elements.
* @see #getChildren()
* @see #getChildrenWithName(javax.xml.namespace.QName)
*/
Iterator<OMElement> getChildElements();
/**
* Add a namespace declaration for the given namespace URI to this element, optionally
* generating a prefix for that namespace.
*
* @param uri
* The namespace to declare in the current scope. The caller is expected to ensure
* that the URI is a valid namespace name.
* @param prefix
* The prefix to associate with the given namespace. The caller is expected to ensure
* that this is a valid XML prefix. If <code>null</code> is
* given, a prefix will be auto-generated.
* @return the created namespace information item
* @throws IllegalArgumentException
* if an attempt is made to bind a prefix to the empty namespace name
* @see #declareNamespace(OMNamespace)
* @see #findNamespace(String, String)
* @see #getAllDeclaredNamespaces()
*/
OMNamespace declareNamespace(String uri, String prefix);
/**
* Add a namespace declaration for the default namespace to this element.
* <p>
* Note that this method will never change the namespace of the element itself. If an attempt is
* made to add a namespace declaration that conflicts with the namespace information of the
* element, an exception is thrown.
*
* @param uri
* The default namespace to declare in the current scope. The caller is expected to
* ensure that the URI is a valid namespace name.
* @return the created namespace information item
* @throws OMException
* if an attempt is made to add a conflicting namespace declaration
*/
OMNamespace declareDefaultNamespace(String uri);
/**
* Get the default namespace in scope on this element.
*
* @return The default namespace or <code>null</code> if no default namespace is in scope. This
* method never returns an {@link OMNamespace} object with an empty namespace URI; if
* the element or one of its ancestors has a {@code xmlns=""} declaration, then
* <code>null</code> is returned. Note that if the method returns an {@link OMNamespace}
* object, then its prefix will obviously be the empty string.
*/
OMNamespace getDefaultNamespace();
/**
* Declares a namespace with the element as its scope.
*
* @param namespace
* The namespace to declare. If the prefix specified by the {@link OMNamespace}
* object is <code>null</code>, then a prefix will be generated.
* @return The declared namespace, which will be equal to the {@link OMNamespace} object passed
* as parameter, except if the prefix was <code>null</code>, in which case the return
* value contains the generated prefix.
* @throws IllegalArgumentException
* if an attempt is made to bind a prefix to the empty namespace name
* @see #declareNamespace(String, String)
* @see #findNamespace(String, String)
* @see #getAllDeclaredNamespaces()
*/
OMNamespace declareNamespace(OMNamespace namespace);
/**
* Add a namespace declaration that undeclares a given prefix. Prefix undeclaring is supported
* in XML 1.1, but forbidden in XML 1.0. If an object model on which this method has been used
* is later serialized to an XML 1.0 document, an error will occur. When serialized to an XML
* 1.1 document, a namespace declaration in the form {@code xmlns:p=""} will be produced.
* <p>
* A namespace declaration with empty namespace name will be added even if no existing namespace
* declaration for the given prefix is in scope in the context of the current element. If a
* namespace declaration for the given prefix is already defined on this element, it will be
* replaced.
* <p>
* The namespace declaration created by this method will be returned by
* {@link #getAllDeclaredNamespaces()}. It is represented as an {@link OMNamespace} object for
* which {@link OMNamespace#getNamespaceURI()} returns an empty string.
*
* @param prefix
* the prefix to undeclare
*/
void undeclarePrefix(String prefix);
/**
* Finds a namespace with the given uri and prefix, in the scope of the hierarchy.
* <p>
* Searches from the current element and goes up the hiararchy until a match is found. If no
* match is found, returns {@code null}.</p>
* <p>
* Either {@code prefix} or {@code uri} should be null. Results are undefined if both are
* specified.
*
* @param uri The namespace to look for. If this is specified, {@code prefix} should be
* null.
* @param prefix The prefix to look for. If this is specified, {@code uri} should be null.
* @return Returns the matching namespace declaration, or {@code null} if none was found.
* @see #declareNamespace(String, String)
* @see #declareNamespace(OMNamespace)
* @see #getAllDeclaredNamespaces()
*/
OMNamespace findNamespace(String uri, String prefix);
/**
* Checks for a namespace in the context of this element with the given prefix and returns the
* relevant namespace object, if available. If not available, returns null.
*
* @param prefix
*/
// TODO: specify if null is a valid argument
// TODO: specify the return value if prefix is the empty string and there is no default namespace
// (should we return null or an OMNamespace instance with namespaceURI and prefix set to ""?)
OMNamespace findNamespaceURI(String prefix);
/**
* Returns an iterator for all of the namespaces declared on this element. Note that this is not
* the same as the set of namespace declarations in scope. Since building a namespace context
* and resolving namespace prefixes has some subtleties associated with it (such as masked
* namespace declarations and prefix undeclaring), it is generally recommended to use one of the
* following specialized methods for this purpose:
* <ul>
* <li>{@link #getNamespacesInScope()} or {@link #getNamespaceContext(boolean)} to calculate the
* namespace context for the element.
* <li>{@link #findNamespace(String, String)} and {@link #findNamespaceURI(String)} to resolve a
* namespace prefix or to find a namespace prefix for a given URI.
* <li>{@link #resolveQName(String)} to resolve a QName literal.
* <li>{@link AXIOMXPath#AXIOMXPath(OMElement, String)} or
* {@link AXIOMXPath#AXIOMXPath(OMAttribute)} to create an XPath expression using the namespace
* context of a given element.
* </ul>
* <p>
* It is expected that applications only rarely use {@link #getAllDeclaredNamespaces()}
* directly.
* <p>
* The iterator returned by this method supports {@link Iterator#remove()} and that method can
* be used to remove a namespace declaration from this element.
*
* @return An iterator over the {@link OMNamespace} items declared on this element. If the
* element has no namespace declarations, an empty iterator is returned.
* <p>
* Note that the returned iterator may be invalidated by a call to
* {@link #declareNamespace(OMNamespace)}, {@link #declareNamespace(String, String)},
* {@link #declareDefaultNamespace(String)} or any other method that modifies the
* namespace declarations of this element.
*/
Iterator<OMNamespace> getAllDeclaredNamespaces();
/**
* Get an iterator that returns all namespaces in scope for this element. This method may be
* used to determine the namespace context for this element. For any given prefix, the iterator
* returns at most one {@link OMNamespace} object with that prefix, and this object specifies
* the namespace URI bound to the prefix. The iterator returns an {@link OMNamespace} object
* with an empty prefix if and only if there is a default namespace. It will never return an
* {@link OMNamespace} object with both the prefix and the namespace URI set to the empty
* string, even if the element or one of its ancestors has a namespace declaration of the form
* {@code xmlns=""}.
* <p>
* The order in which the iterator returns the namespaces is undefined, and invoking the
* {@link Iterator#remove()} method on the returned iterator is not supported. The iterator may
* be a "live" object, which means that results are undefined if the document is modified (in a
* way that would modify the namespace context for the element) while the iterator is in use.
*
* @return an iterator over all namespaces in scope for this element
*/
Iterator<OMNamespace> getNamespacesInScope();
/**
* Get the namespace context of this element, as determined by the namespace declarations
* present on this element and its ancestors.
* <p>
* The method supports two different {@link NamespaceContext} implementation variants:
* <ul>
* <li>A "live" variant that keeps a reference to the element and that performs lookups by
* accessing the object model. This means that any change in the object model will automatically
* be reflected by the {@link NamespaceContext}.
* <li>A "detached" variant that stores a snapshot of the namespace context and that doesn't
* have any reference to the object model.
* </ul>
* <p>
* Typically, creating a live {@link NamespaceContext} is cheaper, but the lookup performance of
* a detached {@link NamespaceContext} is better. The detached variant should always be used if
* the reference to the {@link NamespaceContext} is kept longer than the object model itself,
* because in this case a live {@link NamespaceContext} would prevent the object model from
* being garbage collected.
*
* @param detached
* <code>true</code> if the method should return a detached implementation,
* <code>false</code> if the method should return a live object
* @return The namespace context for this element. Note that the caller must not make any
* assumption about the actual implementation class returned by this method.
*/
NamespaceContext getNamespaceContext(boolean detached);
/**
* Returns a list of OMAttributes.
* <p>
* Note that the iterator returned by this function will be invalidated by any
* {@code addAttribute} call.
*
* @return An iterator over the {@link OMAttribute} items associated with the element. If the
* element has no attributes, an empty iterator is returned.
* @see #getAttribute
* @see #addAttribute(OMAttribute)
* @see #addAttribute(String, String, OMNamespace)
*/
Iterator<OMAttribute> getAllAttributes();
/**
* Returns a named attribute if present.
*
* @param qname the qualified name to search for
* @return Returns an OMAttribute with the given name if found, or null
*/
OMAttribute getAttribute(QName qname);
/**
* Returns a named attribute's value, if present.
*
* @param qname
* the qualified name to search for
* @return The attribute value, or <code>null</code> if no matching attribute is found.
*/
String getAttributeValue(QName qname);
/**
* Adds an attribute to this element.
* <p>
* If the attribute already has an owner, the attribute is cloned (i.e. its name, value and
* namespace are copied to a new attribute) and the new attribute is added to the element.
* Otherwise the existing instance specified by the <code>attr</code> parameter is added to
* the element. In both cases the owner of the added attribute is set to be the particular
* <code>OMElement</code>.
* <p>
* If there is already an attribute with the same name and namespace URI, it will be replaced
* and its owner set to <code>null</code>.
* <p>
* In the particular case where the attribute specified by <code>attr</code> is already owned
* by the element, calling this method has no effect.
* <p>
* Attributes are not stored in any particular order. In particular, there is no guarantee
* that the added attribute will be returned as the last item by the iterator produced by
* a subsequent call to {@link #getAllAttributes()}.
* <p>
* If the attribute being added has a namespace, but no corresponding namespace declaration is
* in scope for the element (i.e. declared on the element or one of its ancestors), a new
* namespace declaration is added to the element. Note that both the namespace prefix and URI
* are taken into account when looking for an existing namespace declaration.
*
* @param attr The attribute to add.
* @return The attribute that was added to the element. As described above this may or may
* not be the same as <code>attr</code>, depending on whether the attribute specified
* by this parameter already has an owner or not.
*/
OMAttribute addAttribute(OMAttribute attr);
/**
* Adds an attribute to this element.
* <p>
* If the element already has an attribute with the same local name and namespace URI, then this
* existing attribute will be removed from the element, i.e. this method will always create a
* new {@link OMAttribute} instance and never update an existing one.
*
* @param localName
* The local name for the attribute.
* @param value
* The string value of the attribute. This function does not check to make sure that
* the given attribute value can be serialized directly as an XML value. The caller
* may, for example, pass a string with the character 0x01.
* @param ns
* The namespace for the attribute. If no corresponding namespace declaration is in
* scope, then a new namespace declaration will be added to the element. The
* {@link OMNamespace} may have a <code>null</code> prefix, in which case the method
* will generate a prefix (if no namespace declaration for the given namespace URI is
* in scope) or use an existing one.
* @return Returns the added attribute.
* @throws IllegalArgumentException
* if an attempt is made to create a prefixed attribute with an empty namespace name
* or an unprefixed attribute with a namespace
*/
OMAttribute addAttribute(String localName, String value, OMNamespace ns);
/**
* Removes the given attribute from this element.
*
* @param attr
* the attribute to remove
* @throws OMException
* if the attribute is not owned by this element
*/
void removeAttribute(OMAttribute attr);
/**
* Returns the first child element of the element.
*
* @return Returns the first child element of the element, or {@code null} if none was found.
*/
OMElement getFirstElement();
/**
* Set the content of this element to the given text. If the element has children, then all
* these children are detached before the content is set. If the parameter is a non empty
* string, then the element will have a single child of type {@link OMText} after the method
* returns. If the parameter is <code>null</code> or an empty string, then the element will have
* no children.
*
* @param text
* the new text content for the element
*/
void setText(String text);
/**
* Set the content of this element to the given {@link QName}. If no matching namespace
* declaration for the {@link QName} is in scope, then this method will add one. If the
* {@link QName} specifies a namespace URI but no prefix, then a prefix will be generated. If
* the element has children, then all these children are detached before the content is set. If
* the parameter is not <code>null</code>, then the element will have a single child of type
* {@link OMText} after the method returns. If the parameter is <code>null</code>, then the
* element will have no children.
*
* @param qname
* the QName value
*/
void setText(QName qname);
/**
* Returns the non-empty text children as a string.
* <p>
* This method iterates over all the text children of the element and concatenates
* them to a single string. Only direct children will be considered, i.e. the text
* is not extracted recursively. For example the return value for
* {@code <element>A<child>B</child>C</element>} will be {@code AC}.
* <p>
* All whitespace will be preserved.
*
* @return A string representing the concatenation of the child text nodes.
* If there are no child text nodes, an empty string is returned.
*/
String getText();
/**
* Returns a stream representing the concatenation of the text nodes that are children of a
* this element. The stream returned by this method produces exactly the same character
* sequence as the the stream created by the following expression:
* <pre>new StringReader(element.getText())</pre>
* <p>
* The difference is that the stream implementation returned by this method is optimized for
* performance and is guaranteed to have constant memory usage, provided that:
* <ol>
* <li>The method is not required to cache the content of the {@link OMElement}, i.e.
* <code>cache</code> is <code>false</code> or the element is an {@link OMSourcedElement} that
* is backed by a non destructive {@link OMDataSource}.
* <li>The underlying parser (or the implementation of the underlying {@link XMLStreamReader} in
* the case of an {@link OMSourcedElement}) is non coalescing. Note that this is not the default
* in Axiom and it may be necessary to configure the parser with
* {@link StAXParserConfiguration#NON_COALESCING}.
* </ol>
* <p>
* When this method is used with {@code cache} set to {@code false} the caller must close the
* returned stream before attempting to access other nodes in the tree.
*
* @param cache
* whether to enable caching when accessing the element
* @return a stream representing the concatenation of the text nodes
*
* @see #getText()
*/
Reader getTextAsStream(boolean cache);
/**
* Write the content of the text nodes that are children of a given element to a {@link Writer}.
* If <code>cache</code> is true, this method has the same effect as the following instruction:
* <pre>out.write(element.getText())</pre>
* <p>
* The difference is that this method is guaranteed to have constant memory usage and is
* optimized for performance (with the same restrictions that apply to
* {@link #getTextAsStream(boolean)}).
* <p>
* The method does <b>not</b> call {@link Writer#close()}.
*
* @param out
* the stream to write the content to
* @param cache
* whether to enable caching when accessing the element
* @throws OMException
* if an error occurs when reading from the element
* @throws IOException
* if an error occurs when writing to the stream
*
* @see #getText()
*/
void writeTextTo(Writer out, boolean cache) throws IOException;
/**
* Resolve the content of this element to a {@link QName}. The QName is interpreted in a way
* that is compatible with the XML schema specification. In particular, surrounding whitespace
* is ignored.
*
* @return the resolved QName, or <code>null</code> if the element is empty or the QName could
* not be resolved
*/
QName getTextAsQName();
/**
* Set the namespace for this element. In addition to changing the namespace URI and prefix of
* the element information item, this method ensures that a corresponding namespace declaration
* exists. If no corresponding namespace declaration is already in scope, then a new one will be
* added to this element.
* <p>
* This method has the same effect as
* {@link OMNamedInformationItem#setNamespace(OMNamespace, boolean)} with <code>declare</code>
* set to <code>true</code>.
*
* @param namespace
* The new namespace for this element, or <code>null</code> to remove the namespace
* from this element. If an {@link OMNamespace} instance with a <code>null</code>
* prefix is given, then a prefix will be generated automatically. In this case, the
* generated prefix can be determined using {@link #getNamespace()}.
* @throws IllegalArgumentException
* if an attempt is made to bind a prefix to the empty namespace name
*/
void setNamespace(OMNamespace namespace);
/**
* @deprecated Use {@link OMNamedInformationItem#setNamespace(OMNamespace, boolean)} with
* <code>declare</code> set to <code>false</code>.
*/
void setNamespaceWithNoFindInCurrentScope(OMNamespace namespace);
/**
* Convenience method to serialize the element to a string with caching enabled. Caching means
* that the object model tree for the element will be fully built in memory and can be accessed
* after invoking this method.
* <p>
* This method produces the same result as {@link OMContainer#serialize(Writer)}. In particular,
* the element is always serialized as plain XML and {@link OMText} nodes containing optimized
* binary data are always inlined using base64 encoding. Since the output is accumulated into a
* single string object, this may result in high memory consumption. Therefore this method
* should be used with care.
*
* @return the serialized object model
*/
@Override
String toString();
/**
* Convenience method to serialize the element to a string without caching. This method will not
* built the object model tree in memory. This means that an attempt to access the object model
* after invoking this method may result in an error (unless the object model was already fully
* built before, e.g. because it was created programmatically).
* <p>
* As for {@link #toString()}, this method may cause high memory consumption for object model
* trees containing optimized binary data and should therefore be used with care.
*
* @return the serialized object model
*/
String toStringWithConsume() throws XMLStreamException;
/**
* Resolves a QName literal in the namespace context defined by this element and produces a
* corresponding {@link QName} object. The implementation uses the algorithm defined by the XML
* Schema specification. In particular, the namespace for an unprefixed QName is the default
* namespace (not the null namespace), i.e. QNames are resolved in the same way as element
* names.
*
* @param qname
* the QName literal to resolve
* @return the {@link QName} object, or <code>null</code> if the QName can't be resolved, i.e.
* if the prefix is not bound in the namespace context of this element
*/
QName resolveQName(String qname);
/**
* Clones this element and its descendants using default options. This method has the same
* effect as {@link #clone(OMCloneOptions)} with default options.
*
* @return the cloned element
*/
OMElement cloneOMElement();
/**
* @deprecated
*/
void setLineNumber(int lineNumber);
/**
* @deprecated
*/
int getLineNumber();
/**
* {@inheritDoc}
*/
@Override
Iterator<OMNode> getDescendants(boolean includeSelf);
}