/* Copyright (c) 2008 Bluendo S.r.L.
* See about.html for details about license.
*
* $Id: Element.java 1132 2009-01-26 16:05:01Z luca $
*/
package it.yup.xmlstream;
// #debug
//@import it.yup.util.Logger;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
public class Element
{
public Vector children;
public Vector attributes;
public String content;
public String name;
public String uri;
// XXX delete?
// inserting time
public long queueTime;
public int maxWait;
private static int _internal_id_counter; //unique id
protected Element() {
children = new Vector();
attributes = new Vector();
uri = null;
name = null;
}
public Element(String uri, String name) {
this.uri = uri;
this.name = name;
children = new Vector();
attributes = new Vector(); //Hashtable();
}
public String getUri(String name) {
return null;
}
// XXX theorically attributes may have prefixes too, but I don't remember any
// jabber packet using them
public String getAttribute(String name) {
for(int i=0; i<attributes.size(); i++) {
String attr[] = (String[]) attributes.elementAt(i);
if(attr[1].equals(name)) {
return attr[2];
}
}
return null;
}
public void setAttribute (String name, String value) {
Enumeration en = attributes.elements();
while(en.hasMoreElements()) {
String triplet[] = (String[]) en.nextElement();
if(triplet[1].equals(name)) {
triplet[2] = value;
return;
}
}
attributes.addElement(new String[] {null,name, value});
}
public void delAttribute (String name) {
Enumeration en = attributes.elements();
while(en.hasMoreElements()) {
String triplet[] = (String[]) en.nextElement();
if(triplet[1].equals(name)) {
attributes.removeElement(triplet);
return;
}
}
}
// easy creation a of child
public Element addElement(String uri, String name) {
Element e = new Element(uri, name);
children.addElement(e);
return e;
}
// set the id attribute to the element, using the static id class field
public static String createUniqueId() {
Element._internal_id_counter++;
return "" + Element._internal_id_counter;
}
/**
* Return the first child having the given name and namespace
* @param uri matched namespace (may be null, in this case any namaspace is ok)
* @param matched name
*/
public Element getChildByName(String uri, String name) {
for(int i=0; i<children.size(); i++) {
Element e = (Element) children.elementAt(i);
if(e.name.equals(name) && (uri == null || e.uri.equals(uri))) {
return e;
}
}
return null;
}
/**
* Return the children having the given name and namespace
* @param uri matched namespace (may be null, in this case any namaspace is ok)
* @param matched name
*/
public Element[] getChildrenByName(String uri, String name) {
Element v[];
int n = 0;
for(int i=0; i<children.size(); i++) {
Element e = (Element) children.elementAt(i);
if(e.name.equals(name) && (uri == null || e.uri.equals(uri))) {
n++;
}
}
v = new Element[n];
n=0;
for(int i=0; i<children.size(); i++) {
Element e = (Element) children.elementAt(i);
if(e.name.equals(name) && (uri == null || e.uri.equals(uri))) {
v[n++] = e;
}
}
return v;
}
public static Element parseDocument(XmlPullParser parser) throws XmlPullParserException, IOException {
Element el = new Element();
parser.require(XmlPullParser.START_DOCUMENT, null, null);
parser.nextToken();
el._parse(parser);
return el;
}
public static Element pullElement(XmlPullParser parser) throws XmlPullParserException, IOException {
Element el = new Element();
el._parse(parser);
return el;
}
public static Element pullDocumentStart(XmlPullParser parser) throws XmlPullParserException, IOException {
Element el = new Element();
el.name = parser.getName();
el.uri = parser.getNamespace();
for(int i = 0; i<parser.getAttributeCount(); i++) {
el.attributes.addElement(new String[] {parser.getAttributeNamespace(i),parser.getAttributeName(i), parser.getAttributeValue(i)});
}
return el;
}
protected void _parse(XmlPullParser parser) throws XmlPullParserException, IOException {
for(int i = 0; i<parser.getAttributeCount(); i++) {
attributes.addElement(new String[] {parser.getAttributeNamespace(i),parser.getAttributeName(i), parser.getAttributeValue(i)});
}
this.name = parser.getName();
this.uri = parser.getNamespace();
boolean finished = false;
StringBuffer textBuffer = null;
do {
int type = parser.nextToken();
switch(type) {
case XmlPullParser.START_TAG:
Element child = new Element();
child._parse(parser);
children.addElement(child);
break;
case XmlPullParser.END_TAG:
finished = true;
break;
case XmlPullParser.COMMENT:
break;
default:
if(parser.getText()!=null) {
if(textBuffer==null) textBuffer = new StringBuffer();
textBuffer.append(parser.getText());
}
}
} while(!finished);
if(textBuffer!=null){
String content = textBuffer.toString();
content.trim();
if(content.length()>0){
this.content = content;
}
}
}
// serialize the element and all its children
public byte[] toXml()
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
KXmlSerializer serializer = new KXmlSerializer();
try {
serializer.setOutput(baos, "UTF-8");
write(serializer);
serializer.endDocument();
serializer.flush();
} catch (IOException e) {
// #debug
//@ Logger.log("[Element:toXml] IOException" + e.getMessage());
}
return baos.toByteArray();
}
private void write(XmlSerializer serializer) {
try {
serializer.setPrefix("", this.uri);
serializer.startTag(this.uri, name);
Enumeration attrEn = attributes.elements();
while(attrEn.hasMoreElements()) {
String attr[] = (String[]) attrEn.nextElement();
serializer.attribute(attr[0], attr[1], attr[2]);
}
Enumeration childEn = children.elements();
while(childEn.hasMoreElements()) {
Element el = (Element) childEn.nextElement();
el.write(serializer);
}
if(content!=null) {
serializer.text(content);
}
serializer.endTag(this.uri, name);
serializer.flush();
} catch (IllegalArgumentException e) {
// #debug
//@ Logger.log("[Element::write] IllegalArgumentException:" + e.getMessage());
} catch (IllegalStateException e) {
// #debug
//@ Logger.log("[Element::write] IllegalStateException: " + e.getMessage());
} catch (IOException e) {
// #debug
//@ Logger.log("[Element::write] IOException: " + e.getMessage());
}
}
public Element(Element e) {
this();
this.name = e.name;
this.uri = e.uri;
this.content = e.content;
for(int i=0; i<e.attributes.size(); i++) {
String triplet[] = (String[]) e.attributes.elementAt(i);
this.attributes.addElement(new String[] {triplet[0], triplet[1],triplet[2]});
}
for(int i=0; i<e.children.size(); i++) {
Element c = (Element) e.children.elementAt(i);
this.children.addElement(c.clone());
}
}
public Element clone() {
Element e = new Element();
e.name = this.name;
e.uri = this.uri;
e.content = this.content;
for(int i=0; i<this.attributes.size(); i++) {
String triplet[] = (String[]) this.attributes.elementAt(i);
e.attributes.addElement(new String[] {triplet[0], triplet[1], triplet[2]});
}
for(int i=0; i<this.children.size(); i++) {
Element c = (Element) this.children.elementAt(i);
e.children.addElement(c.clone());
}
return e;
}
public void serialize(DataOutputStream os) {
try {
os.writeUTF(name==null?"":name);
os.writeUTF(uri==null?"":uri);
os.writeUTF(content==null?"":content);
os.writeShort(attributes.size());
for(int i=0; i<attributes.size(); i++) {
String attr[]=(String[]) attributes.elementAt(i);
// XXX check what happens if null
os.writeUTF(attr[0]);
os.writeUTF(attr[1]);
os.writeUTF(attr[2]);
}
os.writeShort(children.size());
for(int i=0; i<children.size(); i++) {
Element el = (Element) children.elementAt(i);
el.serialize(os);
}
} catch (IOException e) {
e.printStackTrace();
};
}
public static Element load(DataInputStream is) {
Element el = new Element();
try {
el.name = is.readUTF();
el.uri = is.readUTF();
el.content = is.readUTF();
int n = is.readShort();
for(int i=0; i<n; i++) {
String attr[] = new String[3];
attr[0] = is.readUTF();
attr[1] = is.readUTF();
attr[2] = is.readUTF();
el.attributes.addElement(attr);
}
n = is.readShort();
for(int i=0; i<n; i++) {
el.children.addElement(Element.load(is));
}
} catch (IOException e) {
return null;
}
return el;
}
}