繁体   English   中英

如何使用JAXB从一个Java模型生成多个稍微不同的XSD模式?

[英]How to generate multiple, slightly different XSD schemas from one Java model with JAXB?

我有一组相关的Java类,它们可以保存我需要的数据。 下面是我所拥有的简化的类图:

在此处输入图片说明

现在,我需要从XML导入数据,并为此生成XSD模式。 问题是我想要几个这样的XSD架构:

  1. 一种允许导入整个数据图的方法。
  2. 仅允许RootNote.fieldA和ChildNodeA的一种。
  3. 仅允许RootNote.fieldB和ChildNodeB的一种。

我可以使用JAXB(以编程方式)轻松地生成满足nr.1要求的XSD。 但是,对于相同类的nr.2和nr.3,是否有办法做到这一点? 换句话说,似乎我需要JAXB中的“配置文件”之类的东西。

更新:

这是我生成XSD模式的方法:

JAXBContext jc = JAXBContext.newInstance(RootNode.class);

final File baseDir = new File(".");

class MySchemaOutputResolver extends SchemaOutputResolver {
  public Result createOutput( String namespaceUri, String suggestedFileName ) throws IOException {
    return new StreamResult(new File(baseDir,suggestedFileName));
  }
}

jc.generateSchema(new MySchemaOutputResolver());

这不是一个完整的答案,只是一个想法。

您可能使用javax.xml.bind.JAXBContext.generateSchema(SchemaOutputResolver)方法来生成您的模式,因此您基本上使用了特定的JAXBContext实例。 该实例是基于类中的注释构建的。 在构建上下文时,将这些注释读入一个组织成模型的模型,然后将其用于所有操作。

因此,要生成不同的架构,您可能需要创建不同的上下文。 您不能根据情况更改批注,但是可以以不同的方式阅读批注。

看看AnnotationReader 这就是JAXB RI在幕后用来从Java类加载注释的方式。 您可以创建自己的实现,并在创建JAXBContext时使用它。 是类似例子

final AnnotationReader<Type, Class, Field, Method> annotationReader = new AnnoxAnnotationReader();

final Map<String, Object> properties = new HashMap<String, Object>();

properties.put(JAXBRIContext.ANNOTATION_READER, annotationReader);

final JAXBContext context = JAXBContext.newInstance(
    "org.jvnet.annox.samples.po",
    Thread.currentThread().getContextClassLoader(),
    properties);

那么编写自己的注释阅读器(考虑您所谓的“配置文件”)怎么样? 您可以发明自己的注释@XmlSchemaProfile(name="foo") 然后,注释阅读器将检查此注释是否存在所需的值,然后返回它或将其忽略。 您将能够从相同的Java模型构建不同的上下文-从而根据@XmlSchemaProfile批注定义的配置文件生成不同的模式。

我找到了适合我的解决方案。 这个想法是将XSD生成的结果输出到XML文档(内存中的DOM)中。 JAXB允许这样做。 此后,您可以按任何需要的方式操作文档,添加或删除部件。

我写了一些过滤器,将白名单或黑名单字段(在XSD中为元素)和类(在XSD中为复杂类型)过滤。 尽管我发现这种方法有很多潜在的问题,但在我看来,它确实起到了作用。 下面是案例2模式的代码:

// This SchemaOutputResolver implementation saves XSD into DOM
static class DOMResultSchemaOutputResolver extends SchemaOutputResolver  {

    private List<DOMResult> results = new LinkedList<DOMResult>();

    @Override
    public Result createOutput(String ns, String file) throws IOException {
      DOMResult result = new DOMResult();
      result.setSystemId(file);
      results.add(result);
      return result;
    }

    public Document getDocument() {
      return (Document)results.get(0).getNode();
    }

    public String getFilename() {
      return results.get(0).getSystemId();
    }

}

  // This method serializes the DOM into file
  protected void serializeXsdToFile(Document xsdDocument, String filename) throws IOException {
    OutputFormat format = new OutputFormat(xsdDocument);
    format.setIndenting(true);
    FileOutputStream os = new FileOutputStream(filename);
    XMLSerializer serializer = new XMLSerializer(os, format);
    serializer.serialize(xsdDocument);
  }

  @Test
  public void generateSchema2() throws JAXBException, IOException, XPathExpressionException {
    JAXBContext context = JAXBContext.newInstance(RootNode.class);
    DOMResultSchemaOutputResolver schemaOutputResolver = new DOMResultSchemaOutputResolver();

    context.generateSchema(schemaOutputResolver);

    // Do your manipulations here as you want. Below is just an example!
    filterXsdDocumentComplexTypes(schemaOutputResolver.getDocument(), asList("childNodeA"), true);
    filterXsdDocumentElements(schemaOutputResolver.getDocument(), asList("fieldB"));

    serializeXsdToFile(schemaOutputResolver.getDocument(), "xf.xsd");
  }

  private boolean shouldComplexTypeBeDeleted(String complexTypeName, List<String> complexTypes, boolean whitelist) {
    return (whitelist && !complexTypes.contains(complexTypeName)) || (!whitelist && complexTypes.contains(complexTypeName));
  }


  protected void filterXsdDocumentComplexTypes(Document xsdDocument, List<String> complexTypes, boolean whitelist) throws XPathExpressionException {
    XPath xPath = XPathFactory.newInstance().newXPath();
    NodeList complexTypeNodes = (NodeList)xPath.evaluate("//*[local-name() = 'complexType']", xsdDocument, XPathConstants.NODESET);
    for (int i = 0; i < complexTypeNodes.getLength(); i++) {
      Node node = complexTypeNodes.item(i);
      Node complexTypeNameNode = node.getAttributes().getNamedItem("name");

      if (complexTypeNameNode != null) {
        if (shouldComplexTypeBeDeleted(complexTypeNameNode.getNodeValue(), complexTypes, whitelist)) {
          node.getParentNode().removeChild(node);
        }
      }
    }

    NodeList elements = (NodeList)xPath.evaluate("//*[local-name() = 'element']", xsdDocument, XPathConstants.NODESET);
    for (int i = 0; i < elements.getLength(); i++) {
      Node node = elements.item(i);
      Node typeNameNode = node.getAttributes().getNamedItem("type");
      if (typeNameNode != null) {
        if (shouldComplexTypeBeDeleted(typeNameNode.getNodeValue(), complexTypes, whitelist) && !typeNameNode.getNodeValue().startsWith("xs")) {
          node.getParentNode().removeChild(node);
        }
      }
    }
  }

  protected void filterXsdDocumentElements(Document xsdDocument, List<String> blacklistedElements) throws XPathExpressionException {
    XPath xPath = XPathFactory.newInstance().newXPath();

    NodeList elements = (NodeList)xPath.evaluate("//*[local-name() = 'element']", xsdDocument, XPathConstants.NODESET);
    for (int i = 0; i < elements.getLength(); i++) {
      Node node = elements.item(i);
      if (blacklistedElements.contains(node.getAttributes().getNamedItem("name").getNodeValue())) {
        node.getParentNode().removeChild(node);
      }
    }
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM