【问题标题】:Validating markup with StaX and DTD使用 StaX 和 DTD 验证标记
【发布时间】:2016-11-24 15:46:27
【问题描述】:

我有一个简单的 XML 文件和一个代表它的简单 DTD。

我正在处理 假设,即使用 DTD 验证标记是可行的(与我相信的实际模式相反)是最强大和最合适的选项)。

基于这个假设,我想我会尝试使用 StaX。

问题

即使提供了有效的 DTD,StaX 似乎也不会验证任何内容,并且 XML 文件与 DTD 中定义的架构不匹配。

我希望下面的代码会因一些与验证相关的堆栈跟踪而失败,而不是在我的 foo.xml 文件中打印所有元素名称。

我认为我的假设可能存在很大问题,但在我浏览的相关 SO 问题中或其他在线文献中找不到任何具体解释。

下面的代码和资源。

foo.dtd

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT foo (bar+) >
<!ATTLIST foo
    foo CDATA   #REQUIRED
>
<!ELEMENT bar (#PCDATA) >
<!ATTLIST bar
    bar (bar|blah) #REQUIRED
>

foo.xml

<?xml version="1.0" encoding="UTF-8"?>
<foo foo="foo">
<!-- attribute "blah" invalid -->
<bar bar="bar" blah="blah">bar</bar>
<!-- invalid -->
<bar />
</foo>

代码

XMLInputFactory xif = XMLInputFactory.newFactory();

// not sure if this is required? doens't seem to help
xif.setProperty(XMLInputFactory.IS_VALIDATING, "true"); 

// adding dtd
xif.setXMLResolver(
    new XMLResolver() {
        public Object resolveEntity(String publicID, String systemID, String baseURI, String namespace) throws XMLStreamException {
            if ("foo.dtd".equals(systemID)) {
                 return Main.class.getResourceAsStream("foo.dtd");
            }
            else {
                return null;
            }
        };
    }
);
XMLStreamReader reader = null;

try {
    reader = xif.createXMLStreamReader(Main.class.getResourceAsStream("foo.xml"));
    while (reader.hasNext()) {
        switch (reader.next()) {
            // prints local name just for testing 
            // - expecting this to fail at some point
            case XMLStreamReader.START_ELEMENT: 
            System.out.println(reader.getLocalName());
        }

    }
}
finally {
    if (reader != null) {
        try {
            reader.close();
        }
        catch (Exception e) {}
    }
}

输出(期待一些堆栈跟踪)

foo
bar
bar

【问题讨论】:

    标签: java xml dtd stax


    【解决方案1】:

    我看到的第一个问题是您正在测试 systemID ("foo.dtd".equals(systemID)),但您的 XML 文件没有指向 DTD 的系统标识符。

    尝试将带有系统标识符的文档类型声明添加到您的 XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE foo SYSTEM "foo.dtd">
    <foo foo="foo">
        <!-- attribute "blah" invalid -->
        <bar bar="bar" blah="blah">bar</bar>
        <!-- invalid -->
        <bar />
    </foo>
    

    另外,according to this question,您需要使用不同的 StAX 实现,因为默认不支持验证。

    就像该问题的答案中建议的那样,我尝试使用woodstox,将woodstox 5.0.3 jarstax2 api 4.0.0 jar 添加到我的类路径(并将带有系统标识符的文档类型添加到XML)并得到预期的异常:

    foo
    Nov 28, 2016 3:09:53 PM so.test2.SOTest2 main
    SEVERE: null
    com.ctc.wstx.exc.WstxValidationException: Element <bar> has no attribute "blah"
     at [row,col {unknown-source}]: [5,5]
        at com.ctc.wstx.exc.WstxValidationException.create(WstxValidationException.java:50)
        at com.ctc.wstx.sr.StreamScanner.reportValidationProblem(StreamScanner.java:580)
        at com.ctc.wstx.sr.ValidatingStreamReader.reportValidationProblem(ValidatingStreamReader.java:383)
        at com.ctc.wstx.sr.InputElementStack.reportProblem(InputElementStack.java:849)
        at com.ctc.wstx.dtd.DTDValidatorBase.doReportValidationProblem(DTDValidatorBase.java:497)
        at com.ctc.wstx.dtd.DTDValidatorBase.reportValidationProblem(DTDValidatorBase.java:479)
        at com.ctc.wstx.dtd.DTDValidator.validateAttribute(DTDValidator.java:251)
        at com.ctc.wstx.sr.AttributeCollector.validateAttribute(AttributeCollector.java:729)
        at com.ctc.wstx.sr.InputElementStack.resolveAndValidateElement(InputElementStack.java:535)
        at com.ctc.wstx.sr.BasicStreamReader.handleStartElem(BasicStreamReader.java:3059)
        at com.ctc.wstx.sr.BasicStreamReader.nextFromTree(BasicStreamReader.java:2919)
        at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1123)
        at so.test2.SOTest2.main(SOTest2.java:56)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-18
      • 1970-01-01
      • 2011-08-13
      • 2011-11-17
      • 1970-01-01
      • 2018-07-30
      • 2016-01-13
      • 2011-09-30
      相关资源
      最近更新 更多