问题描述
我们使用 Java (org.w3c.dom.Node) 生成 XML,本质上使用
We're generating an XML with Java (org.w3c.dom.Node), using essentially
parent.appendChild(doc.createElement(nodeName));
这会生成一个 XML,其中节点按调用appendChild"的顺序排序.然而,最终的 XML 需要遵守给定的 XSD.我们的代码可以确保有效的值类型、必填字段等都可以.然而,我正在为节点顺序而苦苦挣扎.
this generates an XML where nodes are sorted by the order of calling the 'appendChild'. The final XML, however, needs to adhere to a given XSD. Our code can ensure that valid value types, mandatory fields etc. are ok. I am however struggling with the node order.
有没有办法:
- 在插入时确保节点顺序与 XSD 匹配
- 创建后根据 XSD 对整个 XML 重新排序
澄清一下:
我们拥有的是:
<myNodeA>...</myNodeA>
<myNodeC>...</myNodeC>
<myNodeB>...</myNodeB>
XSD 想要的是:
<myNodeA>...</myNodeA>
<myNodeB>...</myNodeB>
<myNodeC>...</myNodeC>
谢谢,西蒙
推荐答案
我之前通过遍历模式然后从 XML 模型中提取相关部分并沿途流式传输来完成此操作.
I've done this before by traversing the schema and then pulling relevant pieces from the XML model and streaming it along the way.
有多个 xsd 模型库可供使用:
There are multiple xsd model libraries to use:
- xsom
- 练习
- xml架构
这是一个使用 xsom(可以替换为上述之一)和 xom(可以替换为 dom)的示例
Here's an example using xsom (which can be replaced by one of the above) and xom (which can be replaced with dom)
主要:
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)));
}
}
}
实际的重新排序逻辑.您可能需要进一步修改它.例如,我不必为我的项目处理 xsd:any.
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) {}
}
税务作家:
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);
}
}
}
xml 视图:
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 实现:
文档:
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());
}
}
元素:
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();
}
};
}
}
属性:
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();
}
}
这篇关于我可以重新排序现有的 XML 以遵守 XSD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!