我有一组相关的Java类,它们能够保存我需要的数据。下面是我所拥有的简化类图:
现在我需要从XML导入数据,为此我想生成XSD架构。问题是我想要几个这样的XSD架构:
我可以使用JAXB(以编程方式)轻松生成满足nr.1要求的XSD。但对于相同类的情况nr.2和nr.3,有没有办法做到这一点?换句话说,我似乎需要像" profiles"在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());
答案 0 :(得分:0)
这不是一个完整的答案,只是一个想法。
您可能使用javax.xml.bind.JAXBContext.generateSchema(SchemaOutputResolver)
方法生成架构,因此您基本上使用特定的JAXBContext
实例。此实例基于类中的注释构建。在构建上下文时,这些注释被组织成一个模型,然后用于所有操作。
因此,要生成不同的模式,您可能需要创建不同的上下文。您无法更改每个案例的注释,但您可以通过不同方式读取注释。
看看AnnotationReader。这就是JAXB RI在幕后使用从Java类加载注释的方法。您可以创建自己的实现并在创建JAXBContext时使用它。这是一个example of something similar:
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
注释定义的配置文件生成不同的模式。
答案 1 :(得分:0)
我找到了适合我的解决方案。我们的想法是将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);
}
}
}