We\'re generating an XML with Java (org.w3c.dom.Node), using essentially
parent.appendChild(doc.createElement(nodeName));
this gen
I've done this before by traversing the schema and then pulling relevant pieces from the XML model and streaming it along the way.
There are multiple xsd model libraries to use:
Here's an example using xsom (which can be replaced by one of the above) and xom (which can be replaced with dom)
Main:
package main;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
import node.xom.WrappedDocument;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import reorder.xsom.UncheckedXMLStreamWriter;
import reorder.xsom.XSVisitorWriteOrdered;
import com.sun.xml.xsom.XSElementDecl;
import com.sun.xml.xsom.XSSchemaSet;
import com.sun.xml.xsom.parser.XSOMParser;
public class ReorderXmlToXsd {
public static void main(String[] args) throws Exception {
File unorderedXml = new File("unordered.xml");
File xsd = new File("your.xsd");
File orderedXml = new File("ordered.xml");
XSOMParser p = new XSOMParser();
p.parse(xsd);
XSSchemaSet parsed = p.getResult();
Builder xom = new Builder();
Document unorderedDoc = xom.build(unorderedXml);
Element unorderedRoot = unorderedDoc.getRootElement();
XSElementDecl root = parsed.getElementDecl(
unorderedRoot.getNamespaceURI(),
unorderedRoot.getLocalName());
XMLOutputFactory stax = XMLOutputFactory.newInstance();
try (OutputStream to = new FileOutputStream(orderedXml)) {
XMLStreamWriter using = stax.createXMLStreamWriter(to, "UTF-8");
root.visit(
new XSVisitorWriteOrdered(
new WrappedDocument(unorderedDoc),
new UncheckedXMLStreamWriter(using)));
}
}
}
The actual reordering logic. You will probably have to modify this further. For example, I didn't have to deal with the xsd:any for my project.
package reorder.xsom;
import node.WrappedNode;
import com.sun.xml.xsom.*;
import com.sun.xml.xsom.visitor.XSVisitor;
public class XSVisitorWriteOrdered implements XSVisitor {
private final WrappedNode currNode;
private final UncheckedXMLStreamWriter writeTo;
public XSVisitorWriteOrdered(WrappedNode currNode, UncheckedXMLStreamWriter writeTo) {
this.currNode = currNode;
this.writeTo = writeTo;
}
@Override
public void attributeUse(XSAttributeUse use) {
attributeDecl(use.getDecl());
}
@Override
public void modelGroupDecl(XSModelGroupDecl decl) {
modelGroup(decl.getModelGroup());
}
@Override
public void modelGroup(XSModelGroup model) {
for (XSParticle term : model.getChildren()) {
term.visit(this);
}
}
@Override
public void particle(XSParticle particle) {
XSTerm term = particle.getTerm();
term.visit(this);
}
@Override
public void complexType(XSComplexType complex) {
for (XSAttributeUse use : complex.getAttributeUses()) {
attributeUse(use);
}
XSContentType contentType = complex.getContentType();
contentType.visit(this);
}
@Override
public void elementDecl(XSElementDecl decl) {
String namespaceUri = decl.getTargetNamespace();
String localName = decl.getName();
for (WrappedNode child : currNode.getChildElements(namespaceUri, localName)) {
writeTo.writeStartElement(namespaceUri, localName);
XSType type = decl.getType();
type.visit(new XSVisitorWriteOrdered(child, writeTo));
writeTo.writeEndElement();
}
}
@Override
public void attributeDecl(XSAttributeDecl decl) {
String namespaceUri = decl.getTargetNamespace();
String localName = decl.getName();
WrappedNode attribute = currNode.getAttribute(namespaceUri, localName);
if (attribute != null) {
String value = attribute.getValue();
if (value != null) {
writeTo.writeAttribute(namespaceUri, localName, value);
}
}
}
@Override
public void simpleType(XSSimpleType simpleType) {
String value = currNode.getValue();
if (value != null) {
writeTo.writeCharacters(value);
}
}
@Override
public void empty(XSContentType empty) {}
@Override
public void facet(XSFacet facet) {}
@Override
public void annotation(XSAnnotation ann) {}
@Override
public void schema(XSSchema schema) {}
@Override
public void notation(XSNotation notation) {}
@Override
public void identityConstraint(XSIdentityConstraint decl) {}
@Override
public void xpath(XSXPath xp) {}
@Override
public void wildcard(XSWildcard wc) {}
@Override
public void attGroupDecl(XSAttGroupDecl decl) {}
}
Stax writer:
package reorder.xsom;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
public class UncheckedXMLStreamWriter {
private final XMLStreamWriter real;
public UncheckedXMLStreamWriter(XMLStreamWriter delegate) {
this.real = delegate;
}
public void writeStartElement(String namespaceUri, String localName) {
try {
real.writeStartElement(namespaceUri, localName);
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
public void writeEndElement() {
try {
real.writeEndElement();
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
public void writeAttribute(String namespaceUri, String localName, String value) {
try {
real.writeAttribute(namespaceUri, localName, value);
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
public void writeCharacters(String value) {
try {
real.writeCharacters(value);
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
}
}
The xml view:
package node;
import java.util.List;
import javax.annotation.Nullable;
public interface WrappedNode {
List<? extends WrappedNode> getChildElements(String namespaceUri, String localName);
@Nullable
WrappedNode getAttribute(String namespaceUri, String localName);
@Nullable
String getValue();
}
XOM implementation:
Document:
package node.xom;
import java.util.Collections;
import java.util.List;
import node.WrappedNode;
import nu.xom.Document;
import nu.xom.Element;
public class WrappedDocument implements WrappedNode {
private final Document d;
public WrappedDocument(Document d) {
this.d = d;
}
@Override
public List<WrappedElement> getChildElements(String namespaceUri, String localName) {
Element root = d.getRootElement();
if (isAt(root, namespaceUri, localName)) {
return Collections.singletonList(new WrappedElement(root));
}
return Collections.emptyList();
}
@Override
public WrappedAttribute getAttribute(String namespaceUri, String localName) {
throw new UnsupportedOperationException();
}
@Override
public String getValue() {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return d.toString();
}
private static boolean isAt(Element e, String namespaceUri, String localName) {
return namespaceUri.equals(e.getNamespaceURI())
&& localName.equals(e.getLocalName());
}
}
Element:
package node.xom;
import java.util.AbstractList;
import java.util.List;
import node.WrappedNode;
import nu.xom.Attribute;
import nu.xom.Element;
import nu.xom.Elements;
class WrappedElement implements WrappedNode {
private final Element e;
WrappedElement(Element e) {
this.e = e;
}
@Override
public List<WrappedElement> getChildElements(String namespaceUri, String localName) {
return asList(e.getChildElements(localName, namespaceUri));
}
@Override
public WrappedAttribute getAttribute(String namespaceUri, String localName) {
Attribute attribute = e.getAttribute(localName, namespaceUri);
return (attribute != null) ? new WrappedAttribute(attribute) : null;
}
@Override
public String getValue() {
return e.getValue();
}
@Override
public String toString() {
return e.toString();
}
private static List<WrappedElement> asList(final Elements eles) {
return new AbstractList<WrappedElement>() {
@Override
public WrappedElement get(int index) {
return new WrappedElement(eles.get(index));
}
@Override
public int size() {
return eles.size();
}
};
}
}
Attribute:
package node.xom;
import java.util.List;
import node.WrappedNode;
import nu.xom.Attribute;
class WrappedAttribute implements WrappedNode {
private final Attribute a;
WrappedAttribute(Attribute a) {
this.a = a;
}
@Override
public List<WrappedNode> getChildElements(String namespaceUri, String localName) {
throw new UnsupportedOperationException();
}
@Override
public WrappedNode getAttribute(String namespaceUri, String localName) {
throw new UnsupportedOperationException();
}
@Override
public String getValue() {
return a.getValue();
}
@Override
public String toString() {
return a.toString();
}
}
I don't think something like that exists. Simple reordering might be possible, but XML-Schema allows to define so many constraints, that it might be impossible to write a general tool that converts some XML document into a valid document according to some schema.
So, just build the document correctly in the first place.