/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.xml;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.OperationNotSupportedException;
import org.geotools.xml.handlers.xsi.AttributeHandler;
import org.geotools.xml.handlers.xsi.ComplexTypeHandler;
import org.geotools.xml.schema.All;
import org.geotools.xml.schema.Any;
import org.geotools.xml.schema.Attribute;
import org.geotools.xml.schema.AttributeGroup;
import org.geotools.xml.schema.Choice;
import org.geotools.xml.schema.ComplexType;
import org.geotools.xml.schema.Element;
import org.geotools.xml.schema.ElementGrouping;
import org.geotools.xml.schema.Facet;
import org.geotools.xml.schema.Group;
import org.geotools.xml.schema.Schema;
import org.geotools.xml.schema.Sequence;
import org.geotools.xml.schema.SimpleType;
import org.geotools.xml.schema.Type;
import org.geotools.xml.xsi.XSISimpleTypes;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;
/**
* This is the thing that writes documents.
*
* <p>
* This will create valid XML documents, given an object and a schema.
* </p>
*
* @author dzwiers
* @source $URL$
*/
public class DocumentWriter {
/** DOCUMENT ME! */
public static final Logger logger = org.geotools.util.logging.Logging.getLogger(
"net.refractions.xml.write");
private static Level level = Level.WARNING;
/**
* Writer ... include the key to represent true when writing to files,
* include a Writer to write to otherwise.
*/
public static final String WRITE_SCHEMA = "DocumentWriter_WRITE_SCHEMA";
/**
* Element or String ... include a ref to an Element to be used, or a
* string representing the name of the element
*/
public static final String BASE_ELEMENT = "DocumentWriter_BASE_ELEMENT";
/**
* Schema[] or String[]... The order to search the schemas for a valid
* element, either an array of ref to Schema instances or an Array or
* TargetNamespaces
*/
public static final String SCHEMA_ORDER = "DocumentWriter_SCHEMA_ORDER";
/**
* The Encoding which should be used for the Document which should be created.
*/
public static final String ENCODING = "DocumentWriter_ENCODING";
// TODO implement this searchOrder
/**
* boolean ... include the key to use the "nearest" strategy for searching
* schemas. This will be ignored if a schema order was set. When not
* included the schema order as they appear in the orginal schema will be
* used.
*/
public static final String USE_NEAREST = "DocumentWriter_USE_NEAREST";
/** a map of URI->URI representing targetNamespace->Location */
public static final String SCHEMA_LOCATION_HINT = "DocumentWriter_SCHEMA_LOCATION_HINT";
/**
* Sets the logger level
*
* @param l Level
*/
public static void setLevel(Level l) {
level = l;
logger.setLevel(l);
}
/**
* Write value to file using provided schema.
*
* <p>
* Hints:
*
* <ul>
* <li>
* WRITE_SCHEMA - (non null) write to outputfilename.xsd
* </li>
* <li>
* BASE_ELEMENT - (Element) mapping of value to element instance
* </li>
* <li>
* USE_NEAREST - (Boolean) not implemented
* </li>
* <li>
* SCHEMA_ORDER - (String[] or Schema[]) resolve ambiguity & import
* </li>
* </ul>
* </p>
*
* @param value
* @param schema
* @param f
* @param hints
*
* @throws OperationNotSupportedException
* @throws IOException
*
*/
public static void writeDocument(Object value, Schema schema, File f,
Map hints) throws OperationNotSupportedException, IOException {
if ((f == null) || (!f.canWrite())) {
throw new IOException("Cannot write to " + f);
}
if ((hints != null) && hints.containsKey(WRITE_SCHEMA)) {
Map hints2 = new HashMap(hints);
hints2.remove(WRITE_SCHEMA);
File f2 = new File(f.getParentFile(),
f.getName().substring(0, f.getName().indexOf(".")) + ".xsd");
FileWriter wf = new FileWriter(f2);
writeSchema(schema, wf, hints2);
wf.close();
}
FileWriter wf = new FileWriter(f);
writeDocument(value, schema, wf, hints);
wf.close();
}
/**
* Entry Point to Document writer.
*
* <p>
* Hints:
*
* <ul>
* <li>
* WRITE_SCHEMA - (Writer) will be used to write the schema
* </li>
* <li>
* BASE_ELEMENT - (Element) mapping of value to element instance
* </li>
* <li>
* USE_NEAREST - (Boolean) not implemented
* </li>
* <li>
* SCHEMA_ORDER - (String[] or Schema[]) resolve ambiguity & import
* </li>
* </ul>
* </p>
*
* @param value
* @param schema
* @param w
* @param hints optional hints for writing
*
* @throws OperationNotSupportedException
* @throws IOException
*
*/
public static void writeDocument(Object value, Schema schema, Writer w,
Map hints) throws OperationNotSupportedException, IOException {
if ((hints != null) && hints.containsKey(WRITE_SCHEMA)) {
Writer w2 = (Writer) hints.get(WRITE_SCHEMA);
writeSchema(schema, w2, hints);
}
WriterContentHandler wch = new WriterContentHandler(schema, w, hints); // should deal with xmlns declarations
wch.startDocument();
writeFragment(value, wch);
wch.endDocument();
w.flush();
}
/**
* Write value to file using provided schema.
*
* <p>
* Hints:
*
* <ul>
* <li>
* BASE_ELEMENT - (Element) mapping of value to element instance
* </li>
* <li>
* USE_NEAREST - (Boolean) not implemented
* </li>
* <li>
* SCHEMA_ORDER - (String[] or Schema[]) resolve ambiguity & import
* </li>
* </ul>
* </p>
*
* @param value
* @param schema
* @param f
* @param hints
*
* @throws OperationNotSupportedException
* @throws IOException
*
*/
public static void writeFragment(Object value, Schema schema, File f,
Map hints) throws OperationNotSupportedException, IOException {
if ((f == null) || (!f.canWrite())) {
throw new IOException("Cannot write to " + f);
}
FileWriter wf = new FileWriter(f);
writeFragment(value, schema, wf, hints);
wf.close();
}
/**
* Entry Point to Document writer.
*
* <p>
* Hints:
*
* <ul>
* <li>
* BASE_ELEMENT - (Element) mapping of value to element instance
* </li>
* <li>
* USE_NEAREST - (Boolean) not implemented
* </li>
* <li>
* SCHEMA_ORDER - (String[] or Schema[]) resolve ambiguity & import
* </li>
* </ul>
* </p>
*
* @param value
* @param schema
* @param w
* @param hints optional hints for writing
*
* @throws OperationNotSupportedException
* @throws IOException
*
*/
public static void writeFragment(Object value, Schema schema, Writer w,
Map hints) throws OperationNotSupportedException, IOException {
WriterContentHandler wch = new WriterContentHandler(schema, w, hints); // should deal with xmlns declarations
writeFragment(value, wch);
w.flush();
}
private static void writeFragment(Object value, WriterContentHandler wch)
throws OperationNotSupportedException, IOException {
Element e = null;
logger.setLevel(level);
if ((wch.hints != null) && wch.hints.containsKey(BASE_ELEMENT)) {
e = (Element) wch.hints.get(BASE_ELEMENT);
if ((e != null) && (e.getType() != null)) {
e = e.getType().canEncode(e, value, wch.hints) ? e : null;
}
}
if (e == null) {
e = wch.findElement(value);
}
if (e != null) {
Type type = e.getType();
type.encode(e, value, wch, wch.hints);
} else {
throw new OperationNotSupportedException(
"Could not find an appropriate Element to use for encoding of a "
+ ((value == null) ? null : value.getClass().getName()));
}
}
/**
* DOCUMENT ME!
*
* @param schema DOCUMENT ME!
* @param w DOCUMENT ME!
* @param hints DOCUMENT ME!
*
* @throws IOException
*/
public static void writeSchema(Schema schema, Writer w, Map hints)
throws IOException {
WriterContentHandler wch = new WriterContentHandler(schema, w, hints); // should deal with xmlns declarations
Element[] elems = schema.getElements();
if (elems == null) {
throw new IOException("Cannot write for Schema "
+ schema.getTargetNamespace());
}
wch.startDocument();
writeSchema(schema, wch, hints);
wch.endDocument();
}
private static void writeSchema(Schema schema, PrintHandler ph, Map hints)
throws IOException {
if (schema == null) {
return;
}
AttributesImpl ai = new AttributesImpl();
ai.addAttribute("", "targetNamespace", "", "anyUri",
schema.getTargetNamespace().toString());
ai.addAttribute("", "xmlns", "", "anyUri",
XSISimpleTypes.NAMESPACE.toString());
ai.addAttribute("", "xmlns:" + schema.getPrefix(), "", "anyUri",
schema.getTargetNamespace().toString());
Schema[] imports = schema.getImports();
for (int i = 0; i < imports.length; i++) {
ai.addAttribute("", "xmlns:" + imports[i].getPrefix(), "",
"anyUri", imports[i].getTargetNamespace().toString());
}
if ((schema.getId() != null) && (schema.getId() != "")) {
ai.addAttribute("", "id", "", "ID", schema.getId());
}
if ((schema.getVersion() != null) && (schema.getVersion() != "")) {
ai.addAttribute("", "version", "", "String", schema.getVersion());
}
if (schema.isAttributeFormDefault()) {
ai.addAttribute("", "attributeFormDefault", "", "NMTOKEN",
"qualified");
}
if (schema.isElementFormDefault()) {
ai.addAttribute("", "elementFormDefault", "", "NMTOKEN", "qualified");
}
if (schema.getBlockDefault() != Schema.NONE) {
ai.addAttribute("", "blockDefault", "", "NMTOKENS",
ComplexTypeHandler.writeBlock(schema.getBlockDefault()));
}
if (schema.getFinalDefault() != Schema.NONE) {
ai.addAttribute("", "finalDefault", "", "NMTOKENS",
ComplexTypeHandler.writeFinal(schema.getFinalDefault()));
}
ph.startElement(XSISimpleTypes.NAMESPACE, "schema", ai);
for (int i = 0; i < imports.length; i++)
writeImport(imports[i], ph);
Element[] elems = schema.getElements();
if (elems != null) {
for (int i = 0; i < elems.length; i++)
writeElement(elems[i], schema, ph, hints);
}
ComplexType[] cts = schema.getComplexTypes();
if (elems != null) {
for (int i = 0; i < cts.length; i++)
writeComplexType(cts[i], schema, ph, hints);
}
SimpleType[] sts = schema.getSimpleTypes();
if (elems != null) {
for (int i = 0; i < sts.length; i++)
writeSimpleType(sts[i], schema, ph, hints);
}
Group[] groups = schema.getGroups();
if (elems != null) {
for (int i = 0; i < groups.length; i++)
writeGroup(groups[i], schema, ph, hints);
}
Attribute[] attrs = schema.getAttributes();
if (elems != null) {
for (int i = 0; i < attrs.length; i++)
writeAttribute(attrs[i], schema, ph, hints);
}
AttributeGroup[] attrgrps = schema.getAttributeGroups();
if (elems != null) {
for (int i = 0; i < attrgrps.length; i++)
writeAttributeGroup(attrgrps[i], schema, ph, hints);
}
ph.endElement(XSISimpleTypes.NAMESPACE, "schema");
}
private static void writeImport(Schema schema, PrintHandler ph)
throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((schema.getId() != null) && (schema.getId() != "")) {
ai.addAttribute("", "id", "", "ID", schema.getId());
}
ai.addAttribute("", "namespace", "", "anyUri",
schema.getTargetNamespace().toString());
if (schema.getURI() != null) {
ai.addAttribute("", "schemaLocation", "", "anyUri",
schema.getURI().toString());
}
ph.element(XSISimpleTypes.NAMESPACE, "import", ai);
}
private static void writeElement(Element element, Schema schema,
PrintHandler ph, Map hints) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((element.getId() != null) && (element.getId() != "")) {
ai.addAttribute("", "id", "", "ID", element.getId());
}
if (element.getMaxOccurs() != 1) {
ai.addAttribute("", "maxOccurs", "", "Union",
(element.getMaxOccurs() == ElementGrouping.UNBOUNDED) ? "unbounded"
: (""
+ element.getMaxOccurs()));
}
if (element.getMinOccurs() != 1) {
ai.addAttribute("", "minOccurs", "", "ID",
"" + element.getMinOccurs());
}
boolean nested = false;
if (element.getNamespace().equals(schema.getTargetNamespace())) {
// search schema for element, then it's a ref
Element[] elems = schema.getElements();
boolean found = false;
for (int i = 0; (i < elems.length) && !found; i++)
if (element.getName().equals(elems[i].getName())) {
found = true;
ai.addAttribute("", "ref", "", "QName", element.getName());
}
if (!found) {
// type in other NS
if (!element.getType().getNamespace().equals(schema
.getTargetNamespace())) {
found = true;
XSISAXHandler.setLogLevel(logger.getLevel());
Schema s = SchemaFactory.getInstance(element.getNamespace());
if ((element.getName() != null)
&& (element.getName() != "")) {
ai.addAttribute("", "name", "", "QName",
element.getName());
}
ai.addAttribute("", "type", "", "QName",
s.getPrefix() + ":" + element.getType().getName());
}
// search schema for type, then type can be a qName
Type[] types = schema.getComplexTypes();
for (int i = 0; (i < types.length) && !found; i++)
// TODO use equals here
if (element.getType().getName().equals(types[i].getName())) {
found = true;
if ((element.getName() != null)
&& (element.getName() != "")) {
ai.addAttribute("", "name", "", "QName",
element.getName());
}
ai.addAttribute("", "type", "", "QName",
element.getType().getName());
}
types = schema.getSimpleTypes();
for (int i = 0; (i < types.length) && !found; i++)
// TODO use equals here
if (element.getType().getName().equals(types[i].getName())) {
found = true;
if ((element.getName() != null)
&& (element.getName() != "")) {
ai.addAttribute("", "name", "", "QName",
element.getName());
}
ai.addAttribute("", "type", "", "QName",
element.getType().getName());
}
if (!found) {
// we are nested ... log this
nested = true;
if ((element.getName() != null)
&& (element.getName() != "")) {
ai.addAttribute("", "name", "", "QName",
element.getName());
}
}
}
} else {
// use a ref
Schema s = SchemaFactory.getInstance(element.getNamespace());
ai.addAttribute("", "ref", "", "QName",
s.getPrefix() + ":" + element.getName());
}
if (element.isNillable()) {
ai.addAttribute("", "nillable", "", "boolean", "true");
}
if ((element.getDefault() != null) && (element.getDefault() != "")) {
ai.addAttribute("", "default", "", "String", element.getDefault());
} else {
if ((element.getFixed() != null) && (element.getFixed() != "")) {
ai.addAttribute("", "fixed", "", "String", element.getFixed());
}
}
if (element.getSubstitutionGroup() != null) {
String s = "";
if (!element.getSubstitutionGroup().getNamespace().equals(schema
.getTargetNamespace())) {
Schema sss = SchemaFactory.getInstance(element.getSubstitutionGroup()
.getNamespace());
s = sss.getPrefix() + ":";
}
s += element.getSubstitutionGroup().getName();
ai.addAttribute("", "substitutionGroup", "", "QName", s);
}
if (element.isForm()) {
ai.addAttribute("", "form", "", "NMTOKEN", "qualified");
}
if (element.getFinal() != Schema.NONE) {
ai.addAttribute("", "final", "", "NMTOKENS",
ComplexTypeHandler.writeFinal(element.getFinal()));
}
if (element.getBlock() != Schema.NONE) {
ai.addAttribute("", "block", "", "NMTOKENS",
ComplexTypeHandler.writeBlock(element.getBlock()));
}
if (element.isAbstract()) {
ai.addAttribute("", "abstract", "", "boolean", "true");
}
ph.startElement(XSISimpleTypes.NAMESPACE, "element", ai);
if (nested) {
if (element.getType() instanceof ComplexType) {
writeComplexType((ComplexType) element.getType(), schema, ph,
hints);
} else {
writeSimpleType((SimpleType) element.getType(), schema, ph,
hints);
}
}
ph.endElement(XSISimpleTypes.NAMESPACE, "element");
}
private static void writeAttribute(Attribute attribute, Schema schema,
PrintHandler ph, Map hints) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((attribute.getId() != null) && (attribute.getId() != "")) {
ai.addAttribute("", "id", "", "ID", attribute.getId());
}
boolean nested = false;
if (attribute.getNamespace().equals(schema.getTargetNamespace())) {
// search schema for element, then it's a ref
Attribute[] elems = schema.getAttributes();
boolean found = false;
for (int i = 0; (i < elems.length) && !found; i++)
if (attribute.getName().equals(elems[i].getName())) {
found = true;
ai.addAttribute("", "ref", "", "QName", attribute.getName());
}
if (!found) {
// type in other NS
if (!attribute.getSimpleType().getNamespace().equals(schema
.getTargetNamespace())) {
found = true;
XSISAXHandler.setLogLevel(logger.getLevel());
Schema s = SchemaFactory.getInstance(attribute.getNamespace());
if ((attribute.getName() != null)
&& (attribute.getName() != "")) {
ai.addAttribute("", "name", "", "QName",
attribute.getName());
}
ai.addAttribute("", "type", "", "QName",
s.getPrefix() + ":"
+ attribute.getSimpleType().getName());
}
// search schema for type, then type can be a qName
SimpleType[] types = schema.getSimpleTypes();
for (int i = 0; (i < types.length) && !found; i++)
// TODO use equals here
if (attribute.getSimpleType().getName().equals(types[i]
.getName())) {
found = true;
if ((attribute.getName() != null)
&& (attribute.getName() != "")) {
ai.addAttribute("", "name", "", "QName",
attribute.getName());
}
ai.addAttribute("", "type", "", "QName",
attribute.getSimpleType().getName());
}
if (!found) {
// we are nested ... log this
nested = true;
if ((attribute.getName() != null)
&& (attribute.getName() != "")) {
ai.addAttribute("", "name", "", "QName",
attribute.getName());
}
}
}
} else {
// use a ref
Schema s = SchemaFactory.getInstance(attribute.getNamespace());
ai.addAttribute("", "ref", "", "QName",
s.getPrefix() + ":" + attribute.getName());
}
if (attribute.getUse() != Attribute.OPTIONAL) {
ai.addAttribute("", "use", "", "NMTOKEN",
AttributeHandler.writeUse(attribute.getUse()));
}
if ((attribute.getDefault() != null) && (attribute.getDefault() != "")) {
ai.addAttribute("", "default", "", "String", attribute.getDefault());
} else {
if ((attribute.getFixed() != null) && (attribute.getFixed() != "")) {
ai.addAttribute("", "fixed", "", "String", attribute.getFixed());
}
}
if (attribute.isForm()) {
ai.addAttribute("", "form", "", "NMTOKEN", "qualified");
}
ph.startElement(XSISimpleTypes.NAMESPACE, "attribute", ai);
if (nested) {
writeSimpleType(attribute.getSimpleType(), schema, ph, hints);
}
ph.endElement(XSISimpleTypes.NAMESPACE, "attribute");
}
private static void writeGroup(Group group, Schema schema, PrintHandler ph,
Map hints) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((group.getId() != null) && (group.getId() != "")) {
ai.addAttribute("", "id", "", "ID", group.getId());
}
boolean nested = false;
if (group.getNamespace().equals(schema.getTargetNamespace())) {
// search schema for element, then it's a ref
Group[] groups = schema.getGroups();
boolean found = false;
for (int i = 0; (i < groups.length) && !found; i++)
if (group.getName().equals(groups[i].getName())) {
found = true;
ai.addAttribute("", "ref", "", "QName", group.getName());
}
if (!found) {
ai.addAttribute("", "name", "", "QName", group.getName());
nested = true;
}
} else {
// use a ref
XSISAXHandler.setLogLevel(logger.getLevel());
Schema s = SchemaFactory.getInstance(group.getNamespace());
ai.addAttribute("", "ref", "", "QName",
s.getPrefix() + ":" + group.getName());
}
if (group.getMaxOccurs() != 1) {
ai.addAttribute("", "maxOccurs", "", "Union",
(group.getMaxOccurs() == ElementGrouping.UNBOUNDED) ? "unbounded"
: (""
+ group.getMaxOccurs()));
}
if (group.getMinOccurs() != 1) {
ai.addAttribute("", "minOccurs", "", "ID", ""
+ group.getMinOccurs());
}
ph.startElement(XSISimpleTypes.NAMESPACE, "group", ai);
if (nested) {
if (group.getChild().getGrouping() == ElementGrouping.CHOICE) {
writeChoice((Choice) group.getChild(), schema, ph, hints);
} else {
writeSequence((Sequence) group.getChild(), schema, ph, hints);
}
}
ph.endElement(XSISimpleTypes.NAMESPACE, "group");
}
private static void writeAttributeGroup(AttributeGroup attributeGroup,
Schema schema, PrintHandler ph, Map hints) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((attributeGroup.getId() != null) && (attributeGroup.getId() != "")) {
ai.addAttribute("", "id", "", "ID", attributeGroup.getId());
}
boolean nested = false;
if (attributeGroup.getNamespace().equals(schema.getTargetNamespace())) {
// search schema for element, then it's a ref
Group[] groups = schema.getGroups();
boolean found = false;
for (int i = 0; (i < groups.length) && !found; i++)
if (attributeGroup.getName().equals(groups[i].getName())) {
found = true;
ai.addAttribute("", "ref", "", "QName",
attributeGroup.getName());
}
if (!found) {
ai.addAttribute("", "name", "", "QName",
attributeGroup.getName());
nested = true;
}
} else {
// use a ref
XSISAXHandler.setLogLevel(logger.getLevel());
Schema s = SchemaFactory.getInstance(attributeGroup.getNamespace());
ai.addAttribute("", "ref", "", "QName",
s.getPrefix() + ":" + attributeGroup.getName());
}
ph.startElement(XSISimpleTypes.NAMESPACE, "group", ai);
if (nested) {
if (attributeGroup.getAnyAttributeNameSpace() != null) {
ai = new AttributesImpl();
ai.addAttribute("", "namespace", "", "special",
attributeGroup.getAnyAttributeNameSpace());
ph.element(XSISimpleTypes.NAMESPACE, "anyAttribute", ai);
}
if (attributeGroup.getAttributes() != null) {
Attribute[] attrs = attributeGroup.getAttributes();
for (int i = 0; i < attrs.length; i++)
writeAttribute(attrs[i], schema, ph, hints);
}
}
ph.endElement(XSISimpleTypes.NAMESPACE, "group");
}
private static void writeSimpleType(SimpleType simpleType, Schema schema,
PrintHandler ph, Map hints) throws IOException {
if (XSISimpleTypes.NAMESPACE.equals(simpleType.getNamespace())) {
//error - not sure what to do
// TODO log the type error - throw an exception?
}
AttributesImpl ai = new AttributesImpl();
if ((simpleType.getId() != null) && (simpleType.getId() != "")) {
ai.addAttribute("", "id", "", "ID", simpleType.getId());
}
if ((simpleType.getName() != null) && (simpleType.getName() != "")) {
ai.addAttribute("", "name", "", "NCName", simpleType.getName());
}
if (simpleType.getFinal() != Schema.NONE) {
ai.addAttribute("", "final", "", "NMTOKENS",
ComplexTypeHandler.writeFinal(simpleType.getFinal()));
}
ph.startElement(XSISimpleTypes.NAMESPACE, "simpleType", ai);
switch (simpleType.getChildType()) {
case SimpleType.RESTRICTION:
// determine whether to print or reference the child st
SimpleType st = simpleType.getParents()[0];
ai = null;
if (schema.getTargetNamespace().equals(st.getNamespace())) {
if ((st.getName() != null) && (st.getName() != "")) {
SimpleType[] sts = schema.getSimpleTypes();
if (sts != null) {
for (int i = 0; i < sts.length; i++)
if (st.getName().equals(sts[i].getName())) {
ai = new AttributesImpl();
ai.addAttribute("", "base", "", "QName",
st.getName());
}
}
}
} else {
ai = new AttributesImpl();
XSISAXHandler.setLogLevel(logger.getLevel());
Schema s = SchemaFactory.getInstance(st.getNamespace());
ai.addAttribute("", "base", "", "QName",
s.getPrefix() + ":" + st.getName());
}
ph.startElement(XSISimpleTypes.NAMESPACE, "restriction", ai);
if (ai == null) {
writeSimpleType(st, schema, ph, hints);
}
Facet[] facets = simpleType.getFacets();
if (facets != null) {
for (int i = 0; i < facets.length; i++)
writeFacet(facets[i], ph);
}
ph.endElement(XSISimpleTypes.NAMESPACE, "restriction");
break;
case SimpleType.LIST:
// determine whether to print or reference the child st
st = simpleType.getParents()[0];
ai = null;
if (schema.getTargetNamespace().equals(st.getNamespace())) {
if ((st.getName() != null) && (st.getName() != "")) {
SimpleType[] sts = schema.getSimpleTypes();
if (sts != null) {
for (int i = 0; i < sts.length; i++)
if (st.getName().equals(sts[i].getName())) {
ai = new AttributesImpl();
ai.addAttribute("", "itemType", "", "QName",
st.getName());
}
}
}
} else {
ai = new AttributesImpl();
Schema s = SchemaFactory.getInstance(st.getNamespace());
ai.addAttribute("", "itemType", "", "QName",
s.getPrefix() + ":" + st.getName());
}
ph.startElement(XSISimpleTypes.NAMESPACE, "list", ai);
if (ai == null) {
writeSimpleType(st, schema, ph, hints);
}
ph.endElement(XSISimpleTypes.NAMESPACE, "list");
break;
case SimpleType.UNION:
// determine whether to print or reference the child st
SimpleType[] sts = simpleType.getParents();
String memberTypes = null;
List childTs = new LinkedList();
if (sts != null) {
for (int j = 0; j < sts.length; j++) {
st = sts[j];
if (schema.getTargetNamespace().equals(st.getNamespace())) {
boolean found = false;
if ((st.getName() != null) && (st.getName() != "")) {
SimpleType[] sts2 = schema.getSimpleTypes();
if (sts2 != null) {
for (int i = 0; i < sts2.length; i++)
if (st.getName().equals(sts2[i].getName())) {
found = true;
if (memberTypes == null) {
memberTypes = st.getName();
} else {
memberTypes += (" " + st.getName());
}
}
}
}
if (!found) {
childTs.add(st);
}
} else {
ai = new AttributesImpl();
Schema s = SchemaFactory.getInstance(st.getNamespace());
if (memberTypes == null) {
memberTypes = s.getPrefix() + ":" + st.getName();
} else {
memberTypes += (" " + s.getPrefix() + ":"
+ st.getName());
}
}
}
}
if (memberTypes != null) {
ai = new AttributesImpl();
ai.addAttribute("", "memberTypes", "", "QName", memberTypes);
}
ph.startElement(XSISimpleTypes.NAMESPACE, "union", ai);
if (childTs.size() > 0) {
Iterator i = childTs.iterator();
while (i.hasNext())
writeSimpleType((SimpleType) i.next(), schema, ph, hints);
}
ph.endElement(XSISimpleTypes.NAMESPACE, "union");
break;
}
ph.endElement(XSISimpleTypes.NAMESPACE, "simpleType");
}
private static void writeChoice(Choice choice, Schema schema,
PrintHandler ph, Map hints) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((choice.getId() != null) && (choice.getId() != "")) {
ai.addAttribute("", "id", "", "ID", choice.getId());
}
if (choice.getMaxOccurs() != 1) {
ai.addAttribute("", "maxOccurs", "", "Union",
(choice.getMaxOccurs() == ElementGrouping.UNBOUNDED) ? "unbounded"
: (""
+ choice.getMaxOccurs()));
}
if (choice.getMinOccurs() != 1) {
ai.addAttribute("", "minOccurs", "", "ID",
"" + choice.getMinOccurs());
}
ph.startElement(XSISimpleTypes.NAMESPACE, "choice", ai);
ElementGrouping[] egs = choice.getChildren();
if (egs != null) {
for (int i = 0; i < egs.length; i++)
if (egs[i] != null) {
switch (egs[i].getGrouping()) {
case ElementGrouping.ALL:
writeAll((All) egs[i], schema, ph, hints);
break;
case ElementGrouping.ANY:
writeAny((Any) egs[i], ph);
break;
case ElementGrouping.CHOICE:
writeChoice((Choice) egs[i], schema, ph, hints);
break;
case ElementGrouping.ELEMENT:
writeElement((Element) egs[i], schema, ph, hints);
break;
case ElementGrouping.GROUP:
writeGroup((Group) egs[i], schema, ph, hints);
break;
case ElementGrouping.SEQUENCE:
writeSequence((Sequence) egs[i], schema, ph, hints);
break;
}
}
}
ph.endElement(XSISimpleTypes.NAMESPACE, "choice");
}
private static void writeSequence(Sequence sequence, Schema schema,
PrintHandler ph, Map hints) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((sequence.getId() != null) && (sequence.getId() != "")) {
ai.addAttribute("", "id", "", "ID", sequence.getId());
}
if (sequence.getMaxOccurs() != 1) {
ai.addAttribute("", "maxOccurs", "", "Union",
(sequence.getMaxOccurs() == ElementGrouping.UNBOUNDED) ? "unbounded"
: (""
+ sequence.getMaxOccurs()));
}
if (sequence.getMinOccurs() != 1) {
ai.addAttribute("", "minOccurs", "", "ID",
"" + sequence.getMinOccurs());
}
ph.startElement(XSISimpleTypes.NAMESPACE, "sequence", ai);
ElementGrouping[] egs = sequence.getChildren();
if (egs != null) {
for (int i = 0; i < egs.length; i++)
if (egs[i] != null) {
switch (egs[i].getGrouping()) {
case ElementGrouping.ANY:
writeAny((Any) egs[i], ph);
break;
case ElementGrouping.CHOICE:
writeChoice((Choice) egs[i], schema, ph, hints);
break;
case ElementGrouping.ELEMENT:
writeElement((Element) egs[i], schema, ph, hints);
break;
case ElementGrouping.GROUP:
writeGroup((Group) egs[i], schema, ph, hints);
break;
case ElementGrouping.SEQUENCE:
writeSequence((Sequence) egs[i], schema, ph, hints);
break;
}
}
}
ph.endElement(XSISimpleTypes.NAMESPACE, "sequence");
}
private static void writeAll(All all, Schema schema, PrintHandler ph,
Map hints) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((all.getId() != null) && (all.getId() != "")) {
ai.addAttribute("", "id", "", "ID", all.getId());
}
if (all.getMaxOccurs() != 1) {
ai.addAttribute("", "maxOccurs", "", "Union",
(all.getMaxOccurs() == ElementGrouping.UNBOUNDED) ? "unbounded"
: (""
+ all.getMaxOccurs()));
}
if (all.getMinOccurs() != 1) {
ai.addAttribute("", "minOccurs", "", "ID", "" + all.getMinOccurs());
}
ph.startElement(XSISimpleTypes.NAMESPACE, "all", ai);
Element[] egs = all.getElements();
if (egs != null) {
for (int i = 0; i < egs.length; i++)
if (egs[i] != null) {
writeElement(egs[i], schema, ph, hints);
}
}
ph.endElement(XSISimpleTypes.NAMESPACE, "all");
}
private static void writeAny(Any any, PrintHandler ph) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((any.getId() != null) && (any.getId() != "")) {
ai.addAttribute("", "id", "", "ID", any.getId());
}
if (any.getMaxOccurs() != 1) {
ai.addAttribute("", "maxOccurs", "", "Union",
(any.getMaxOccurs() == ElementGrouping.UNBOUNDED) ? "unbounded"
: (""
+ any.getMaxOccurs()));
}
if (any.getMinOccurs() != 1) {
ai.addAttribute("", "minOccurs", "", "ID", "" + any.getMinOccurs());
}
if (any.getNamespace() != null) {
ai.addAttribute("", "namespace", "", "special",
"" + any.getNamespace());
}
ph.element(XSISimpleTypes.NAMESPACE, "any", ai);
}
private static void writeComplexType(ComplexType complexType,
Schema schema, PrintHandler ph, Map hints) throws IOException {
AttributesImpl ai = new AttributesImpl();
if ((complexType.getId() != null) && (complexType.getId() != "")) {
ai.addAttribute("", "id", "", "ID", complexType.getId());
}
if ((complexType.getName() != null) && (complexType.getName() != "")) {
ai.addAttribute("", "name", "", "NCName", complexType.getName());
}
if (complexType.isAbstract()) {
ai.addAttribute("", "abstract", "", "boolean", "true");
}
if (complexType.getFinal() != Schema.NONE) {
ai.addAttribute("", "final", "", "NMTOKENS",
ComplexTypeHandler.writeFinal(complexType.getFinal()));
}
if (complexType.getBlock() != Schema.NONE) {
ai.addAttribute("", "block", "", "NMTOKENS",
ComplexTypeHandler.writeBlock(complexType.getBlock()));
}
if (complexType.isMixed()) {
ai.addAttribute("", "mixed", "", "boolean", "true");
}
ph.startElement(XSISimpleTypes.NAMESPACE, "complexType", ai);
ElementGrouping egs = complexType.getChild();
complexType.getChild();
// TODO determine if this complexType isDerived ... and make a complexContent or Simplecontent to match
if (egs != null) {
switch (egs.getGrouping()) {
// TODO determine if this will work
// case ElementGrouping.COMPLEXCONTENT:
// writeAny((ComplexContent)egs,schema,ph,hints);
// break;
// case ElementGrouping.SIMPLECONTENT:
// writeAny((SimpleContent)egs,schema,ph,hints);
// break;
case ElementGrouping.ALL:
writeAll((All) egs, schema, ph, hints);
break;
case ElementGrouping.CHOICE:
writeChoice((Choice) egs, schema, ph, hints);
break;
case ElementGrouping.GROUP:
writeGroup((Group) egs, schema, ph, hints);
break;
case ElementGrouping.SEQUENCE:
writeSequence((Sequence) egs, schema, ph, hints);
break;
}
}
if (complexType.getAnyAttributeNameSpace() != null) {
ai = new AttributesImpl();
ai.addAttribute("", "namespace", "", "special",
complexType.getAnyAttributeNameSpace());
ph.element(XSISimpleTypes.NAMESPACE, "anyAttribute", ai);
}
// TODO think about checking for attribute groupings?
// add a Attribute.getParentGroup() ... null or Group
if (complexType.getAttributes() != null) {
Attribute[] attrs = complexType.getAttributes();
for (int i = 0; i < attrs.length; i++)
writeAttribute(attrs[i], schema, ph, hints);
}
ph.endElement(XSISimpleTypes.NAMESPACE, "complexType");
}
private static void writeFacet(Facet facet, PrintHandler ph) throws IOException {
if (facet == null) {
return;
}
AttributesImpl ai = new AttributesImpl();
ai.addAttribute("", "value", "", "ID", facet.getValue());
switch (facet.getFacetType()) {
case Facet.ENUMERATION:
ph.element(XSISimpleTypes.NAMESPACE, "enumeration", ai);
break;
case Facet.FRACTIONDIGITS:
ph.element(XSISimpleTypes.NAMESPACE, "fractionDigits", ai);
break;
case Facet.LENGTH:
ph.element(XSISimpleTypes.NAMESPACE, "length", ai);
break;
case Facet.MAXEXCLUSIVE:
ph.element(XSISimpleTypes.NAMESPACE, "maxExclusive", ai);
break;
case Facet.MAXINCLUSIVE:
ph.element(XSISimpleTypes.NAMESPACE, "maxInclusive", ai);
break;
case Facet.MAXLENGTH:
ph.element(XSISimpleTypes.NAMESPACE, "maxLength", ai);
break;
case Facet.MINEXCLUSIVE:
ph.element(XSISimpleTypes.NAMESPACE, "minExclusive", ai);
break;
case Facet.MININCLUSIVE:
ph.element(XSISimpleTypes.NAMESPACE, "minInclusive", ai);
break;
case Facet.MINLENGTH:
ph.element(XSISimpleTypes.NAMESPACE, "minLength", ai);
break;
case Facet.PATTERN:
ph.element(XSISimpleTypes.NAMESPACE, "pattern", ai);
break;
case Facet.TOTALDIGITS:
ph.element(XSISimpleTypes.NAMESPACE, "totalDigits", ai);
break;
case Facet.WHITESPACE:
ph.element(XSISimpleTypes.NAMESPACE, "whiteSpace", ai);
break;
}
}
private static class WriterContentHandler implements PrintHandler {
private boolean firstElement = true; // needed for NS declarations
private Writer writer;
private Map prefixMappings; // when the value is null it has not been included yet into the document ...
private Schema schema;
protected Map hints;
private Schema[] searchOrder = null;
private String encoding = "UTF-8";
WriterContentHandler(Schema schema, Writer writer, Map hints) {
this.writer = writer;
this.schema = schema;
this.hints = hints;
if (this.hints != null){
Object encodingValue = this.getHint(DocumentWriter.ENCODING);
if (encodingValue != null){
this.encoding = encodingValue.toString();
}
}
prefixMappings = new HashMap();
prefixMappings.put(schema.getTargetNamespace(), "");
Schema[] imports = schema.getImports();
if (imports != null) {
for (int i = 0; i < imports.length; i++)
prefixMappings.put(imports[i].getTargetNamespace(),
imports[i].getPrefix());
}
}
private void printXMLNSDecs(Map arg0) throws IOException {
Schema[] imports = getSchemaOrdering();
String s = "";
Map schemaLocs = (Map) ((arg0 == null) ? null
: arg0.get(SCHEMA_LOCATION_HINT));
schemaLocs = (schemaLocs == null) ? new HashMap() : schemaLocs;
for (int i = 0; i < imports.length; i++) {
if(imports[i] !=null){
if (imports[i] == schema) {
writer.write(" xmlns=\"" + schema.getTargetNamespace()
+ "\"");
if ((schema.getURI() != null)
&& !schema.getTargetNamespace().equals(schema
.getURI())) {
String endResult = schema.getURI().toString();
endResult=endResult.replaceAll("&", "&");
s = schema.getTargetNamespace() + " " + endResult;
}
} else {
writer.write(" xmlns:" + imports[i].getPrefix() + "=\""
+ imports[i].getTargetNamespace() + "\"");
}
URI location = imports[i].getURI();
boolean forced = false;
if (schemaLocs.containsKey(imports[i].getTargetNamespace())) {
location = (URI) schemaLocs.get(imports[i]
.getTargetNamespace());
forced = true;
}
if ((location != null) && location.isAbsolute()) {
if (imports[i].includesURI(location) || forced) {
if ((location != null)
&& !location.equals(
imports[i].getTargetNamespace())) {
String endResult = location.toString();
endResult=endResult.replaceAll("&", "&");
s += (" " + imports[i].getTargetNamespace() + " "
+ endResult);
}
}
}
}}
s = s.trim();
if (!"".equals(s)) {
writer.write(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
writer.write(" xsi:schemaLocation=\"" + s + "\"");
}
}
/**
* @see PrintHandler#startElement(URI, String, Attributes)
*
* @param namespaceURI URI
* @param localName String
* @param attributes Attributes
*/
public void startElement(URI namespaceURI, String localName,
Attributes attributes) throws IOException {
String prefix = (String) prefixMappings.get(namespaceURI);
if (prefix != null) {
if (!prefix.equals("")) {
prefix = prefix + ":";
}
} else {
if (namespaceURI.equals(schema.getTargetNamespace())) {
prefix = "";
} else {
XSISAXHandler.setLogLevel(logger.getLevel());
prefix = SchemaFactory.getInstance(namespaceURI).getPrefix();
if (prefix == null) {
prefix = "";
}
if (prefix != "") {
prefix += ":";
}
}
}
writer.write("<");
writer.write(prefix + localName);
if (firstElement) {
printXMLNSDecs(hints);
firstElement = false;
}
if (attributes != null) {
for (int i = 0; i < attributes.getLength(); i++) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
writer.write(" ");
writer.write(name);
writer.write("=\"");
writer.write(value);
writer.write("\"");
}
}
writer.write(">");
// TODO format here
// writer.write("\n");
}
/**
* @see PrintHandler#element(URI, String, Attributes)
*
* @param namespaceURI URI
* @param localName String
* @param attributes Attributes
*/
public void element(URI namespaceURI, String localName,
Attributes attributes) throws IOException {
String prefix = (String) prefixMappings.get(namespaceURI);
if (prefix != null) {
if (!prefix.equals("")) {
prefix = prefix + ":";
}
} else {
if (namespaceURI.equals(schema.getTargetNamespace())) {
prefix = "";
} else {
XSISAXHandler.setLogLevel(logger.getLevel());
prefix = SchemaFactory.getInstance(namespaceURI).getPrefix();
if (prefix == null) {
prefix = "";
}
if (prefix != "") {
prefix += ":";
}
}
}
writer.write("<");
writer.write(prefix + localName);
if (firstElement) {
printXMLNSDecs(hints);
firstElement = false;
}
if (attributes != null) {
for (int i = 0; i < attributes.getLength(); i++) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
writer.write(" ");
writer.write(name);
writer.write("=\"");
writer.write(value);
writer.write("\"");
}
}
writer.write("/>");
// TODO format here
writer.write("\n");
}
/**
* @see PrintHandler#endElement(URI, String)
* @param namespaceURI URI
* @param localName String
*/
public void endElement(URI namespaceURI, String localName)
throws IOException {
String prefix = (String) prefixMappings.get(namespaceURI);
if (prefix != null) {
if (!prefix.equals("")) {
prefix = prefix + ":";
}
} else {
if (namespaceURI.equals(schema.getTargetNamespace())) {
prefix = "";
} else {
XSISAXHandler.setLogLevel(logger.getLevel());
prefix = SchemaFactory.getInstance(namespaceURI).getPrefix();
if (prefix == null) {
prefix = "";
}
if (prefix != "") {
prefix += ":";
}
}
}
writer.write("</");
writer.write(prefix + localName);
writer.write(">");
// TODO format here
writer.write("\n");
}
/**
* @see PrintHandler#characters(char[], int, int)
* @see Writer#write(char[], int, int)
* @param arg0
* @param arg1
* @param arg2
*/
public void characters(char[] arg0, int arg1, int arg2)
throws IOException {
writer.write(arg0, arg1, arg2);
}
/**
* @see PrintHandler#characters(String)
* @see Writer#write(java.lang.String)
* @param s String
*/
public void characters(String s) throws IOException {
writer.write(s);
}
/**
* @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int,
* int)
* @see Writer#write(char[], int, int)
* @param arg0
* @param arg1
* @param arg2
* @throws IOException
*/
public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
throws IOException {
writer.write(arg0, arg1, arg2);
}
/**
* @see PrintHandler#startDocument()
*/
public void startDocument() throws IOException {
writer.write("<?xml version=\"1.0\" encoding=\""+encoding+"\"?>");
// TODO format here
writer.write("\n");
}
/**
* @see PrintHandler#endDocument()
*/
public void endDocument() throws IOException {
// TODO format here
writer.write("\n");
writer.flush();
}
/**
* @see PrintHandler#getDocumentSchema()
*/
public Schema getDocumentSchema() {
return schema;
}
/**
* @see PrintHandler#getHint(Object)
*/
public Object getHint(Object key) {
return hints.get(key);
}
/**
* @see PrintHandler#findElement(Object)
*/
public Element findElement(Object value) {
Schema[] searchOrder1;
try {
searchOrder1 = getSchemaOrdering();
} catch (IOException e) {
logger.warning(e.toString());
return null;
}
for (int i = 0; i < searchOrder1.length; i++) {
Element[] elems = searchOrder1[i].getElements();
if (elems != null) {
for (int j = 0; j < elems.length; j++)
if ((elems[j].getType() != null)
&& elems[j].getType().canEncode(elems[j],
value, hints)) {
return elems[j];
}
}
}
return null;
}
/**
* @see PrintHandler#findElement(String)
*/
public Element findElement(String name) {
Schema[] searchOrder1;
try {
searchOrder1 = getSchemaOrdering();
} catch (IOException e) {
logger.warning(e.toString());
return null;
}
for (int i = 0; i < searchOrder1.length; i++) {
Element[] elems = searchOrder1[i].getElements();
if (elems != null) {
for (int j = 0; j < elems.length; j++)
if ((elems[j].getName() != null)
&& elems[j].getName().equals(name)) {
return elems[j];
}
}
}
return null;
}
private Schema[] getSchemaOrdering() throws IOException {
if (searchOrder != null) {
return searchOrder;
}
if (((hints == null) || (hints.get(SCHEMA_ORDER) == null))
&& ((schema.getImports() == null)
|| (schema.getImports().length == 0))) {
searchOrder = new Schema[] { schema, };
} else {
List so = new LinkedList();
if ((hints != null) && hints.containsKey(SCHEMA_ORDER)) {
Object order = hints.get(SCHEMA_ORDER);
List targNS = new LinkedList();
targNS.add(schema.getTargetNamespace());
if (schema.getImports() != null) {
for (int i = 0; i < schema.getImports().length; i++)
if (!targNS.contains(
schema.getImports()[i]
.getTargetNamespace())) {
targNS.add(schema.getImports()[i]
.getTargetNamespace());
}
}
if (order instanceof Schema[]) {
Schema[] sOrder = (Schema[]) order;
for (int i = 0; i < sOrder.length; i++) {
int nsIndex = targNS.indexOf(sOrder[i]
.getTargetNamespace());
if (nsIndex >= 0) { // found
so.add(sOrder[i]);
targNS.remove(nsIndex);
}
}
} else {
String[] stringOrder = (String[]) order;
for (int i = 0; i < stringOrder.length; i++) {
int nsIndex = targNS.indexOf(stringOrder[i]);
try {
if (nsIndex >= 0) { // found
URI uri = new URI(stringOrder[i]);
XSISAXHandler.setLogLevel(logger.getLevel());
so.add(SchemaFactory.getInstance(uri));
targNS.remove(nsIndex);
} else {
URI uri = new URI(stringOrder[i]);
so.add(SchemaFactory.getInstance(uri));
}
} catch (URISyntaxException e) {
logger.warning(e.toString());
IOException t = new IOException(e.toString());
t.initCause(e);
throw t;
}
}
}
if (!targNS.contains(schema.getTargetNamespace())) {
so.add(schema);
}
for (int i = 0; i < schema.getImports().length; i++) {
int nsIndex = targNS.indexOf(schema.getImports()[i]
.getTargetNamespace());
if (nsIndex >= 0) { // found
so.add(schema.getImports()[i]);
targNS.remove(nsIndex);
}
}
} else {
if ((hints != null) && hints.containsKey(USE_NEAREST)) {
// TODO fill this in
so.add(schema);
for (int i = 0; i < schema.getImports().length; i++)
so.add(schema.getImports()[i]);
} else {
so.add(schema);
for (int i = 0; i < schema.getImports().length; i++)
so.add(schema.getImports()[i]);
}
}
searchOrder = (Schema[]) so.toArray(new Schema[so.size()]);
}
return searchOrder;
}
}
}