使用版本属性解决用于XML文档的XML Schema版本

时间:2012-08-17 13:47:54

标签: java xml xsd sax jaxp

我必须编写一些代码来处理读取和验证XML文档,这些文档在其根元素中使用version属性来声明版本号,如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
<Junk xmlns="urn:com:initech:tps" 
    xmlns:xsi="http://www3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="urn:com:initech.tps:schemas/foo/Junk.xsd"
    VersionAttribute="2.0">

有一堆嵌套模式,我的代码有org.w3c.dom.ls.LsResourceResolver来确定要使用的模式,实现此方法:

LSInput resolveResource(String type,
                        String namespaceURI,
                        String publicId,
                        String systemId,
                        String baseURI)

架构的早期版本已将架构版本嵌入到命名空间中,因此我可以使用namespaceURI和systemId来决定提供哪个架构。现在版本号已切换到根元素中的属性,我的解析器无法访问该元素。我如何在LsResourceResolver中找出XML文档的版本?

2 个答案:

答案 0 :(得分:3)

我的建议

  1. 使用SAX或DOM解析文档
  2. 获取版本属性
  3. 使用Validator.validate(Source)方法并使用已经解析的文档(来自步骤1),如下所示
  4. 从已解析的文档构建DOMSource

    DocumentBuilder builder = factory.newDocumentBuilder();
    Document document = builder.parse(new File(args[0]));
    
    domSource = new DOMSource(document);
    

答案 1 :(得分:3)

我之前从未处理过架构版本,也不知道涉及到什么。当版本是命名空间的一部分时,我可以将所有模式放在一起并让它们被整理出来,但是根元素和版本中的版本在版本之间共享,无法从XML中读取版本信息< em>在开始SAX解析之前。

我将做一些非常类似于Pangea建议的内容(从我那里获得+1),但我无法完全遵循这些建议,因为文档太大而无法将其全部读入内存,甚至一次。通过使用STAX,我可以最大限度地减少从文件中获取版本所需的工作量。请参阅此DeveloperWorks文章"Screen XML documents efficiently with StAX"

  

XML文档的筛选或分类是一个常见问题,   特别是在XML中间件中。将XML文档路由到特定的   处理器可能需要分析文档类型和   文件内容。这里的问题是获得所需   来自文档的信息具有最小的开销。   传统的解析器(如DOM或SAX)不太适合这种情况   任务。例如,DOM解析整个文档并构造一个   在将控制权返回给内存之前,在内存中完成文档树   客户。甚至是使用延迟节点扩展的DOM解析器,因此   能够部分解析文档,有很高的资源需求   因为文档树必须至少部分构造在   记忆。这对于筛选目的来说是不可接受的。

获取版本信息的代码如下所示:

def map = [:]
def startElementCount = 0
def inputStream = new File(inputFile).newInputStream()
try {
    XMLStreamReader reader = 
        XMLInputFactory.newInstance().createXMLStreamReader(inputStream)
    for (int event; (event = reader.next()) != XMLStreamConstants.END_DOCUMENT;) {
        if (event == XMLStreamConstants.START_ELEMENT) {
            if (startElementCount > 0) return map
            startElementCount += 1
            map.rootElementName = reader.localName
            for (int i = 0; i < reader.attributeCount; i++) {
                if (reader.getAttributeName(i).toString() == 'VersionAttribute') {
                    map.versionIdentifier = reader.getAttributeValue(i).toString()
                    return map
                }
            }
        }
    }   
} finally {
    inputStream.close()
}

然后我可以使用版本信息来确定要使用的解析器以及要在SaxFactory上设置的架构文档。