使用模式按照模式重新排序XML文档的元素

ska*_*man 5 java xml xsd xsom

假设我有一个XML文档(表示为文本,W3C DOM,无论如何),还有一个XML Schema.XML文档具有模式定义的所有正确元素,但顺序错误.

如何使用模式"重新排序"文档中的元素以符合模式定义的顺序?

我知道这应该是可能的,可能使用XSOM,因为JAXB XJC代码生成器使用元素的正确序列化顺序来注释其生成的类.

但是,我不熟悉XSOM API,它非常密集,所以我希望你们中的一个人有一些经验,可以指出我正确的方向.像"在这个父元素中允许哪些子元素,以什么顺序?"之类的东西.


让我举个例子.

我有一个像这样的XML文档:

<A>
   <Y/>
   <X/>
</A>
Run Code Online (Sandbox Code Playgroud)

我有一个XML Schema,它说<A>必须是一个<X>后跟a的内容<Y>.现在显然,如果我尝试根据模式验证文档,它会失败,因为<X>并且<Y>顺序错误.但我知道我的文档提前是"错误的",所以我还没有使用模式进行验证.不过,我知道,我的文档具有所有正确的元素由模式只是在错误的顺序定义.

我想要做的是以编程方式检查Schema(可能使用XSOM - 这是XML Schema的对象模型),并询问它<A>应该是什么内容.API将公开"您需要<X>后跟a <Y>"的信息.

所以我使用我的XML文档(使用DOM API)并相应地重新安排,以便现在文档将根据模式进行验证.

了解XSOM在这里是什么很重要 - 它是一个java API,它表示XML Schema中包含的信息,而不是我的实例文档中包含的信息.

我不想做的是从架构生成代码,因为架构在构建时是未知的.此外,XSLT没有用,因为元素的正确排序仅由模式中包含的数据字典决定.

希望现在已经足够明确了.

小智 5

我被同样的问题困扰了大约两周。终于我得到了突破。这可以使用 JAXB 编组/解组功能来实现。

在 JAXB marshal/unmarshal 中,XML 验证是一个可选功能。因此,在创建 Marshaller 和 UnMarshaller 对象时,我们不调用 setSchema(schema) 方法。省略此步骤可以避免 marshal/unmarshal 的 XML 验证功能。

所以现在,

  1. 如果 XML 中不存在任何 XSD 强制元素,则会被忽略。
  2. 如果 XSD 中不存在的任何标签存在于 XML 中,则不会引发错误,并且它不会出现在编组/解组后获得的新 XML 中。
  3. 如果元素不按顺序排列,则会重新排序。这是由 JAXB 生成的 POJO 完成的,我们在创建 JAXBContext 时传递这些 POJO。
  4. 如果某个元素被错误地放置在其他标记内,那么它会在新的 XML 中被省略。编组/解组时不会引发错误。

public class JAXBSequenceUtil {
  public static void main(String[] args) throws JAXBException, IOException {

    String xml = FileUtils.readFileToString(new File(
            "./conf/out/Response_103_1015700001&^&IOF.xml"));

    System.out.println("Before marshalling : \n" + xml);
    String sequencedXml = correctSequence(xml,
            "org.acord.standards.life._2");
    System.out.println("After marshalling : \n" + sequencedXml);
  }

  /**
   * @param xml
   *            - XML string to be corrected for sequence.
   * @param jaxbPackage
   *            - package containing JAXB generated classes using XSD.
   * @return String - xml with corrected sequence
   * @throws JAXBException
   */
  public static String correctSequence(String xml, String jaxbPackage)
        throws JAXBException {
    JAXBContext jaxbContext = JAXBContext.newInstance(jaxbPackage);
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    Object txLifeType = unmarshaller.unmarshal(new InputSource(
            new StringReader(xml)));
    System.out.println(txLifeType);

    StringWriter stringWriter = new StringWriter();
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.marshal(txLifeType, stringWriter);

    return stringWriter.toString();
  }
}
Run Code Online (Sandbox Code Playgroud)


Wim*_*ink 2

您的问题转化为:您有一个与架构不匹配的 XSM 文件,并且您希望将其转换为有效的文件。

使用 XSOM,您可以读取 XSD 中的结构,或许还可以分析 XML,但它仍然需要从无效表单到有效表单的额外映射。使用样式表会容易得多,因为您将遍历 XML,使用 XPath 节点以正确的顺序处理元素。对于 XML,如果您希望先有苹果,后有梨,则样式表将首先复制苹果节点 (/Fruit/Apple),然后再复制梨节点。这样,无论旧文件中的顺序如何,它们在新文件中的顺序都是正确的。

您可以使用 XSOM 读取 XSD 并生成对数据重新排序的样式表。然后使用该样式表转换 XML。一旦 XSOM 为 XSD 生成了样式表,您就可以重复使用该样式表,直到 XSD 被修改或需要另一个 XSD。

当然,您可以使用 XSOM 以正确的顺序立即复制节点。但是,由于这意味着您的代码必须自行遍历所有节点和子节点,因此可能需要一些时间才能完成处理。样式表可以做同样的事情,但是转换器将能够更快地处理它。它可以直接处理数据,而 Java 代码必须通过 XMLDocument 属性获取/设置每个节点。


因此,我将使用 XSOM 为 XSD 生成样式表,该样式表只需逐个节点复制 XML 即可反复重复使用。仅当 XSD 更改时才需要重写样式表,并且它的执行速度比 Java API 需要遍历节点本身时更快。样式表不关心顺序,因此它总是以正确的顺序结束。
为了使其更有趣,您可以跳过 XSOM 并尝试使用读取 XSD 的样式表以从中生成另一个样式表。生成的样式表将按照样式表中定义的确切顺序复制 XML 节点。会很复杂吗?实际上,样式表需要为每个元素生成模板,并确保该元素中的子元素以正确的顺序处理。

当我想到这一点时,我想知道以前是否已经这样做过。它将非常通用并且能够处理几乎所有 XSD/XML。

让我们看看...使用“//xsd:element/@name”您将获得架构中的所有元素名称。每个唯一的名称都需要翻译成模板。在这些模板中,您需要处理特定元素的子节点,这稍微复杂一些。元素可以有一个参考,您需要遵循该参考。否则,获取它的所有子 xsd:element 节点。

  • 我不知道,模式可能非常复杂,尤其是我正在使用的模式......扩展类型,替换组,所有这些东西。可怕的。 (2认同)