/*
* $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/util/XMLValue.java,v 1.3.2.2 2004/02/05 16:05:14 mholz Exp $
* $Revision: 1.3.2.2 $
* $Date: 2004/02/05 16:05:14 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* 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 org.apache.slide.util;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.structure.SubjectNode;
import org.jdom.CDATA;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.EntityRef;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.ProcessingInstruction;
import org.jdom.Text;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
/**
* This class is a container for a list of JDOM Elements.
* The {@link #toString toString()} method provides a XML document fragment
* describing the Elements of this XMLValue.
*
* @version $Revision: 1.3.2.2 $
*
* @author <a href="mailto:ralf.stuckert@softwareag.com">Ralf Stuckert</a>
**/
public class XMLValue implements Cloneable, Comparable {
/**
* Constant for the message of the IllegalArgumentException that may be
* thrown in method {@link #add add()}.
*/
public static final String ELEMENT_MUST_NOT_BE_NULL = "'null' Element is not allowed";
/**
* Constant for the message of the IllegalArgumentException that may be
* thrown in constructor {@link #XMLValue(List) XMLValue(List)}.
*/
public static final String TYPE_MISMATCH = "Only objects of type Element are allowed";
/**
* The start tag used to create a valid document out of the XML Element list
* string in constructor {@link #XMLValue(String) XMLValue(String)}.
*/
protected static final String START_TAG = "<root>";
/**
* The end tag used to create a valid document out of the XML Element list
* string in constructor {@link #XMLValue(String) XMLValue(String)}.
*/
protected static final String END_TAG = "</root>";
protected static final String E_HREF = "href";
/**
* The list of JDOM Elements.
*/
protected ArrayList elementList = null;
/**
* Creates a XMLValue.
*/
public XMLValue() {
this((List)null);
}
/**
* Creates a XMLValue from the given <code>element</code>.
*
* @param element the JDOM Element to add to the list.
*
* @throws IllegalArgumentException if the given <code>element</code>
* is <code>null</code>.
*/
public XMLValue(Element element) throws IllegalArgumentException {
this((List)null);
add(element);
}
/**
* Creates a XMLValue from the given <code>list</code> of JDOM Elements.
* the given List may be <code>null</code>.
*
* @param elementList the list of JDOM Elements to add.
*
* @throws IllegalArgumentException if one of the list items
* is <code>null</code> or not a
* <code>Element</code>.
*/
public XMLValue(List elementList) throws IllegalArgumentException{
this.elementList = new ArrayList();
add(elementList);
}
/**
* Creates a XMLValue from the given String representation of a
* list of XML Elements.
*
* @param xmlString a String representation of a list of XML Elements.
*
* @throws JDOMException if parsing the <code>xmlString</code> fails.
*/
public XMLValue(String xmlString) throws JDOMException {
this(xmlString, null);
}
/**
* Creates a XMLValue from the given String representation of a
* list of XML Elements. If the given <code>defaultNamespace</code> is not
* <code>null</code>, all nodes that does not have any namespace will be
* created with that Namespace.
*
* @param xmlString a String representation of a list of XML Elements.
* @param defaultNamespace the Namespace to use to create nodes that
* does not have any namespace.
* May be <code>null</code>.
*
* @throws JDOMException if parsing the <code>xmlString</code> fails.
*/
public XMLValue(String xmlString, Namespace defaultNamespace) throws JDOMException {
this((List)null);
add(xmlString, defaultNamespace);
}
/**
* Adds a JDOM Element.
*
* @param element the JDOM Element to add.
*
* @throws IllegalArgumentException if the given <code>element</code>
* is <code>null</code>.
*/
public void add(Element element) throws IllegalArgumentException {
if (element == null) {
throw new IllegalArgumentException(ELEMENT_MUST_NOT_BE_NULL);
}
elementList.add(element);
}
/**
* Adds a JDOM Text.
*
* @param text the JDOM Text to add.
*
* @throws IllegalArgumentException if the given <code>text</code>
* is <code>null</code>.
*/
public void add(Text text) throws IllegalArgumentException {
if (text == null) {
throw new IllegalArgumentException(ELEMENT_MUST_NOT_BE_NULL);
}
elementList.add(text);
}
/**
* Adds a JDOM Comment.
*
* @param comment the JDOM Comment to add.
*
* @throws IllegalArgumentException if the given <code>comment</code>
* is <code>null</code>.
*/
public void add(Comment comment) throws IllegalArgumentException {
if (comment == null) {
throw new IllegalArgumentException(ELEMENT_MUST_NOT_BE_NULL);
}
elementList.add(comment);
}
/**
* Adds a JDOM ProcessingInstruction.
*
* @param pi the JDOM ProcessingInstruction to add.
*
* @throws IllegalArgumentException if the given <code>pi</code>
* is <code>null</code>.
*/
public void add(ProcessingInstruction pi) throws IllegalArgumentException {
if (pi == null) {
throw new IllegalArgumentException(ELEMENT_MUST_NOT_BE_NULL);
}
elementList.add(pi);
}
/**
* Adds a JDOM CDATA.
*
* @param cdata the JDOM CDATA to add.
*
* @throws IllegalArgumentException if the given <code>CDATA</code>
* is <code>null</code>.
*/
public void add(CDATA cdata) throws IllegalArgumentException {
if (cdata == null) {
throw new IllegalArgumentException(ELEMENT_MUST_NOT_BE_NULL);
}
elementList.add(cdata);
}
/**
* Adds a JDOM EntityRef.
*
* @param eref the JDOM EntityRef to add.
*
* @throws IllegalArgumentException if the given <code>entity ref</code>
* is <code>null</code>.
*/
public void add(EntityRef eref) throws IllegalArgumentException {
if (eref == null) {
throw new IllegalArgumentException(ELEMENT_MUST_NOT_BE_NULL);
}
elementList.add(eref);
}
/**
* Adds a List of JDOM items.
*
* @param content the list of JDOM items to add.
*
* @throws IllegalArgumentException if one of the list items
* is <code>null</code> or not a
* <code>Element</code>.
*/
public void add(List content) throws IllegalArgumentException {
if (content != null) {
Iterator iterator = content.iterator();
while (iterator.hasNext()) {
Object o = iterator.next();
if( o == null ) {
throw new IllegalArgumentException(ELEMENT_MUST_NOT_BE_NULL);
}
else if( o instanceof Element ) {
add((Element)o);
}
else if( o instanceof Text ) {
Text t = (Text)o;
t.setText( t.getTextTrim() );
add(t);
}
else if( o instanceof Comment ) {
add((Comment)o);
}
else if( o instanceof ProcessingInstruction ) {
add((ProcessingInstruction)o);
}
else if( o instanceof CDATA ) {
add((CDATA)o);
}
else if( o instanceof EntityRef ) {
add((EntityRef)o);
}
else {
throw new IllegalArgumentException(TYPE_MISMATCH);
}
}
}
}
/**
* Adds the Elements given by an XML string representation.
*
* @param xmlString a String representation of a list of XML Elements.
*
* @throws JDOMException if parsing the <code>xmlString</code> fails.
*/
public void add(String xmlString) throws JDOMException {
add(xmlString, null);
}
/**
* Adds the Elements given by an XML string representation. If the given
* <code>namespace</code> is not <code>null</code>, all nodes that does not
* have any namespace will be created with that Namespace.
*
* @param xmlString a String representation of a list of XML Elements.
* @param defaultNamespace the Namespace to use to create nodes that
* does not have any namespace.
* May be <code>null</code>.
*
* @throws JDOMException if parsing the <code>xmlString</code> fails.
*/
public void add(String xmlString, Namespace defaultNamespace) throws JDOMException {
if (xmlString != null) {
StringBuffer buffer = new StringBuffer(START_TAG.length() +
xmlString.length() +
END_TAG.length());
buffer.append(START_TAG);
buffer.append(xmlString);
buffer.append(END_TAG);
SAXBuilder builder = new SAXBuilder();
if (defaultNamespace != null) {
builder.setXMLFilter(new DefaultNamespaceXMLFilter(defaultNamespace));
}
try {
Document document = builder.build(new StringReader(buffer.toString()));
List content = document.getRootElement().getContent();
add( content );
// detach elements from parent
content.clear();
}
catch (Exception e) {
// should not happen since the StringReader does not
// perform any "real" I/O
throw new JDOMException(e.getMessage());
}
}
}
public void addHref(String path) {
Element href = new Element(E_HREF, NodeProperty.NamespaceCache.DEFAULT_NAMESPACE);
href.setText(path);
add(href);
}
/**
* Method getHrefs
*
* @return a List of URIs (String)
*
*/
public List getHrefStrings() {
List result = new ArrayList();
Iterator i = iterator();
while (i.hasNext()) {
Object o = i.next();
if (o instanceof Element && E_HREF.equals(((Element)o).getName())) {
result.add(((Element)o).getTextTrim());
}
}
return result;
}
/**
* Method getHrefs
*
* @return a List of nodes (SubjectNode)
*
*/
public List getHrefNodes() {
List result = new ArrayList();
Iterator i = iterator();
while (i.hasNext()) {
Object o = i.next();
if (o instanceof Element && E_HREF.equals(((Element)o).getName())) {
result.add(SubjectNode.getSubjectNode(((Element)o).getTextTrim()));
}
}
return result;
}
public void stripServletContext(String servletContext) {
Iterator i = iterator();
while (i.hasNext()) {
Object o = i.next();
if (o instanceof Element && E_HREF.equals(((Element)o).getName())) {
Element hrefElm = (Element)o;
String href = hrefElm.getTextTrim();
if (href.startsWith(servletContext)) {
hrefElm.setContent(java.util.Arrays.asList(
new Text[]{new Text(href.substring(servletContext.length()))}));
}
}
}
}
/**
* Returns an iterator of JDOM Elements.
*
* @return an iterator of JDOM Elements.
*/
public Iterator iterator() {
return elementList.iterator();
}
/**
* Returns the amount of JDOM elements.
*
* @return the amount of JDOM elements.
*/
public int size() {
return elementList.size();
}
/**
* Returns a clone of the List of JDOM Elements.
*
* @return a clone of the List of JDOM Elements.
*/
public List getList() {
return (List)elementList.clone();
}
/**
* Returns <code>true</code> if the other object is an XMLValue and
* both their String representations are equal.
*
* @param other the Object to test for equality.
*
* @return <code>true</code> if the other object is an XMLValue and
* both their String representations are equal.
*/
public boolean equals(Object other) {
if ( ! (other instanceof XMLValue) ) {
return false;
}
return (this.toString().equals(other.toString()));
}
/**
* Returns the hash code of this instance.
*
* @return the hash code of this instance.
*/
public int hashCode() {
return toString().hashCode();
}
/**
* Returns a clone of this instance.
*
* @return a clone of this instance.
*/
public Object clone() {
return new XMLValue(elementList);
}
/**
* Returns a String representation of the Elements as a XML document fragment.
*
* @return a String representation of the Elements.
*/
public String toString() {
XMLOutputter outputter = new XMLOutputter();
StringWriter stringWriter = new StringWriter();
Iterator iterator = elementList.iterator();
while (iterator.hasNext()) {
try {
Object o = iterator.next();
if( o instanceof Element ) {
outputter.output((Element)o, stringWriter);
}
else if( o instanceof Text ) {
outputter.output((Text)o, stringWriter);
}
else if( o instanceof Comment ) {
outputter.output((Comment)o, stringWriter);
}
else if( o instanceof ProcessingInstruction ) {
outputter.output((ProcessingInstruction)o, stringWriter);
}
else if( o instanceof CDATA ) {
outputter.output((CDATA)o, stringWriter);
}
else if( o instanceof EntityRef ) {
outputter.output((EntityRef)o, stringWriter);
}
}
catch (IOException e) {
// this should not happen since we're writing to a StringWriter
// which is no 'real' I/O
throw new RuntimeException("IOException occurred: " + e.getMessage());
}
}
return stringWriter.toString();
}
/**
* This XMLFilter uses the given namespace as the default, means if no
* namespace is provided.
*/
protected static class DefaultNamespaceXMLFilter extends XMLFilterImpl {
/**
* The namespace to use as default.
*/
Namespace defaultNamespace = null;
/**
* Creates a DefaultNamespaceXMLFilter which uses the given
* <code>defaultNamespace</code> as default namespace, means if no
* namespace is provided.
*
* @param defaultNamespace the Namespace to use as default.
* Must NOT be <code>null</code>.
*/
public DefaultNamespaceXMLFilter(Namespace defaultNamespace) {
this.defaultNamespace = defaultNamespace;
}
/**
* Overwrite <code>startElement()</code> in order to provide the
* <code>defaultNamespace</code> if the current Element does not have
* any namespace.
*
* @param namespaceURI the URI of the Namespace.
* @param localName the name of the Element without any namspace
* prefix.
* @param qName the full name of the Element (with the namespace
* prefix if there is one).
* @param atts the Attributes of the element.
*
* @throws SaxException
*/
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
if ( (namespaceURI == null) || (namespaceURI.length() == 0) ) {
namespaceURI = defaultNamespace.getURI();
qName = defaultNamespace.getPrefix() + ":" + qName;
}
super.startElement(namespaceURI, localName, qName, atts);
}
/**
* Overwrite <code>endElement()</code> in order to provide the
* <code>defaultNamespace</code> if the current Element does not have
* any namespace.
*
* @param namespaceURI the URI of the Namespace.
* @param localName the name of the Element without any namspace
* prefix.
* @param qName the full name of the Element (with the namespace
* prefix if there is one).
*
* @throws SaxException
*/
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
if ( (namespaceURI == null) || (namespaceURI.length() == 0) ) {
namespaceURI = defaultNamespace.getURI();
qName = defaultNamespace.getPrefix() + ":" + qName;
}
super.endElement(namespaceURI, localName, qName);
}
}
/**
* concatenates the text() values of all Elements in elementList
*
* @return a String
*
*/
public String getTextValue() {
Iterator it = elementList.iterator();
StringBuffer sb = new StringBuffer();
while (it.hasNext()) {
Object o = it.next();
if (o instanceof Element) {
sb.append (((Element)o).getTextTrim());
}
}
return sb.toString();
}
/**
* compares the concatenated Text values of all Elements in elementList
*
* @param o an Object
*
* @return an int
*
*/
public int compareTo (Object o) {
String s1 = getTextValue();
String s2 = ((XMLValue)o).getTextValue();
return s1.compareTo (s2);
}
}