sxf4j/src/main/java/com/moparisthebest/sxf4j/impl/XomXmlElement.java

193 lines
5.2 KiB
Java
Executable File

package com.moparisthebest.sxf4j.impl;
import nu.xom.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class XomXmlElement extends AbstractXmlElement {
private final Element internal;
public XomXmlElement() {
internal = null;
}
public XomXmlElement(Element internal) {
this.internal = internal;
}
private XomXmlElement(String name, Element parent) {
internal = new Element(name);
if (parent == null)
return;
String nameSpaceUri = parent.getNamespaceURI();
if (nameSpaceUri != null)
internal.setNamespaceURI(nameSpaceUri);
parent.appendChild(internal);
}
@Override
public String getName() {
return internal.getQualifiedName();
}
@Override
public String getValue() {
return internal.getValue();
}
@Override
public String getAttribute(String name) {
// Xom doesn't allow xmlns(:.*)? to be attributes, but we want them to be, so implement that here
if (name.equals("xmlns"))
return emptyForNull(internal.getNamespaceURI());
String nameSpaceStart = "xmlns:";
if (name.startsWith(nameSpaceStart) && name.length() > nameSpaceStart.length()) {
return emptyForNull(internal.getNamespaceURI(name.split(":")[1]));
}
// otherwise it's a regular attribute
Attribute attr = internal.getAttribute(name);
return attr == null ? null : attr.getValue();
}
@Override
public String[] getAttributeNames() {
String[] ret = new String[internal.getAttributeCount()+internal.getNamespaceDeclarationCount()];
int x = 0;
for(; x < internal.getAttributeCount(); ++x)
ret[x] = internal.getAttribute(x).getQualifiedName();
// special handling for xmlns, again...
for(int y = 0; y < internal.getNamespaceDeclarationCount(); ++y){
String name = internal.getNamespacePrefix(y);
name = name.isEmpty() ? "xmlns" : ("xmlns:"+name);
ret[x++] = name;
}
return ret;
}
@Override
public XmlElement getParent() {
return wrapParent(internal.getParent());
}
@Override
public int getChildCount() {
return internal.getChildCount();
}
@Override
public XmlElement[] getChildren(String name){
Elements nl = internal.getChildElements();
List<XmlElement> ret = new ArrayList<XmlElement>(nl.size());
for(int x = 0; x < nl.size(); ++x){
Element n = nl.get(x);
if(name == null || name.equals(n.getQualifiedName()))
ret.add(new XomXmlElement(n));
}
return ret.toArray(new XmlElement[ret.size()]);
}
@Override
public XmlElement getChild(String name) {
if(name == null)
return null;
//Element child = internal.getFirstChildElement(name, internal.getNamespaceURI());
//return child == null ? null : new XomXmlElement(child);
// in order to avoid namespace issues, we need to call getChildElements and find them ourselves...
Elements elements = internal.getChildElements();
for(int x = 0; x < elements.size(); ++x){
Element element = elements.get(x);
if(name.equals(element.getQualifiedName()))
return new XomXmlElement(element);
}
return null;
}
@Override
public XmlElement setAttribute(String name, String value) {
if (name.startsWith("xmlns"))
try {
String prefix = name.split(":")[1];
internal.addNamespaceDeclaration(prefix, value);
} catch (Exception e) {
if (name.equals("xmlns"))
internal.setNamespaceURI(value);
else
internal.addAttribute(new Attribute(name, value));
}
else
internal.addAttribute(new Attribute(name, value));
return this;
}
@Override
public XmlElement setValue(String value) {
internal.appendChild(value);
return this;
}
@Override
public XmlElement getNewChildXmlElement(String name) {
return new XomXmlElement(name, internal);
}
@Override
public XmlElement addChild(XmlElement other) {
if (other instanceof XomXmlElement) {
XomXmlElement o = (XomXmlElement) other;
internal.appendChild(o.internal);
}
return this;
}
@Override
public XmlElement readFromStream(InputStream is) throws Exception {
Builder parser = new Builder();
Document doc = parser.build(is);
if(doc == null)
return null;
return new XomXmlElement(doc.getRootElement());
}
@Override
public void writeToStream(OutputStream os) throws Exception {
final Serializer serializer;
Element toWrite = internal;
if(internal.getParent() != null){
// then we already have a parent, so can't create a new document, so print a copy of this object
toWrite = new Element(toWrite);
serializer = new Serializer(os, "UTF-8"){
@Override
protected void writeXMLDeclaration() throws IOException {
// we don't want this for a child
}
};
}else
serializer = new Serializer(os, "UTF-8");
serializer.setIndent(2);
//serializer.setMaxLength(64); // line length
serializer.write(new Document(toWrite));
os.close();
}
@Override
protected Object getInternal() {
return this.internal;
}
@Override
protected XmlElement wrapObject(Object internal) {
if(internal instanceof Element)
return new XomXmlElement((Element)internal);
return null;
}
}