2013-03-14 2 views
1

Мы генерации XML с Java (org.w3c.dom.Node), с использованием в основномМогу ли я изменить порядок существующий XML придерживаться к XSD

parent.appendChild(doc.createElement(nodeName)); 

это создает XML где узлы сортируются по порядку вызова «appendChild». Конечный XML, однако, должен придерживаться данного XSD. Наш код может гарантировать, что допустимые типы значений, обязательные поля и т. Д. В порядке. Однако я борюсь с порядком узлов.

Есть ли подход либо:

  • На вставке убедитесь, что порядок узлов соответствует XSD
  • Re порядка весь XML после создания в соответствии с XSD

Для уточнения :

Что мы имеем:

<myNodeA>...</myNodeA> 
<myNodeC>...</myNodeC> 
<myNodeB>...</myNodeB> 

А что XSD хочет:

<myNodeA>...</myNodeA> 
<myNodeB>...</myNodeB> 
<myNodeC>...</myNodeC> 

Спасибо, Саймон

+0

Вы зацикливание по именам узлов для того, чтобы выполнить parent.appendChild (doc.createElement (NODENAME)); вызов. Закажите коллекцию, через которую вы зацикливаете до вызова appendChild – DwB

ответ

2

Я сделал это раньше, пройдя схему, а затем вытаскивая соответствующие фрагменты из модели XML и передавая ее по пути.

Есть несколько библиотек XSD модели использовать:

  • xsom
  • Xerces
  • XMLSCHEMA

Ниже приведен пример с использованием xsom (который может быть заменен одним из указанных выше) и xom (который может быть заменен на дом)

Главная:

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 для моего проекта.

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 Автор:

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(); 
    } 
} 
+0

Это выглядит как смехотворная работа, чтобы исправить то, что вы могли бы легко сделать в первую очередь ... но хорошо, может быть, это решает какую-то проблему, о которой я не знаю ... –

+1

Ха-ха, действительно. Это было сделано, потому что вход xsd/xml не был известен раньше, поэтому очистка должна была выполняться динамически. – slow

+0

@slow: Это похоже на то, что я искал. Я проверю, действительно ли наш код не может создать XML-совместимый XML-код. Но если нет, я попробую применить вышеприведенный подход. Благодаря! – Simon

0

Я не думаю, что что-то подобное существует. Простое переупорядочение может быть возможным, но XML-Schema позволяет определить так много ограничений, что может быть невозможно написать общий инструмент, который преобразует некоторый XML-документ в действительный документ в соответствии с некоторой схемой.

Итак, просто создайте документ правильно в первую очередь.

+0

Я знаю обо всех возможных ограничениях ... но это действительно исключительно переупорядочение, с которым я связан. – Simon