14.5 使用DTD验证一个XML文档
问题
如何根据一个DTD来验证一个XML文档?
解决方案
使用Xerces类库中的SAX2(XML的简单API)或者DOM解析器。
为了使用SAX2来验证XML文档,你需要获取一个SAX2XMLReader,如示例14-8中那样。接下来,通过参数xercesc::XMLUni::fgSAX2CoreValidation和true来调用解析器的setFeature()方法打开DTD合法性验证功能。最后,注册一个ErrorHandler方法来接收DTD违反通知,并且以你的XML文档名作为参数来调用解析器的parse()方法。
为了使用DOM来验证XML文档,首先你需要构造一个XercesDOMParser实例。接下来,以参数xercesc::XercesDOMParser::Val_Always调用解析器的setValidationScheme()方法来打开DTD验证功能。最后,注册一个ErrorHandler类接收DTD违反通知,并且使用你的XML文档名作为参数来调用这个解析器的parse()方法。
注意: 这里我使用类XercesDOMParser,这个解析器是Xerces的一部分,这个部分是在DOM3标准的DOMBuilder接口之前引入的。使用XercesDOMParser更简单,但是你还是可以使用DOMBuilder。请参考14.4节的讨论。
例如,假设你想修改来自示例14-1中的XML文档animals.xml使得它包含一个外在的DTD引用,如示例14-11和14-12中说明的那样。使用SAX2 API来验证这个XML文档的合法性的代码在示例14-13中;而使用DOM解析器来验证这个XML文档的代码在示例14-14中。
示例14-11 XML文档animals.xml的DTD animals.dtd文件
<!-- DTD for Feldman Family Circus Animals -->
<!ELEMENT animalList (animal+)>
<!ELEMENT animal ( name, species, dateOfBirth,
veterinarian, trainer ) >
<!ELEMENT name (#PCDATA)>
<!ELEMENT species (#PCDATA)>
<!ELEMENT dateOfBirth (#PCDATA)>
<!ELEMENT veterinarian EMPTY>
<!ELEMENT trainer EMPTY>
<!ATTLIST veterinarian
name CDATA #REQUIRED
phone CDATA #REQUIRED
>
<!ATTLIST trainer
name CDATA #REQUIRED
phone CDATA #REQUIRED
>
示例14-12 修改后的包含DTD的animals.xml文档
<?xml version="1.0" encoding="UTF-8"?>
<!-- Feldman Family Circus Animals with DTD -->
<!DOCTYPE animalList SYSTEM "animals.dtd">
<!-- same as Example 14-1 -->
</animalList>
示例14-13 使用SAX2 API来验证animals.xml的DTD的合法性
/*
* Same includes as Example 14-8, except <vector> is not needed
*/
#include <stdexcept> // runtime_error
#include <xercesc/sax2/DefaultHandler.hpp>
using namespace std;
using namespace xercesc;
/*
* Define XercesInitializer as in Example 14-8
* and CircusErrorHandler as in Example 14-7
*/
int main()
{
try {
// Initialize Xerces and obtain a SAX2 parser
XercesInitializer init;
auto_ptr<SAX2XMLReader>
parser(XMLReaderFactory::createXMLReader());
// Enable validation
parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
// Register error handler to receive notifications
// of DTD violations
CircusErrorHandler error;
parser->setErrorHandler(&error);
parser->parse("animals.xml");
} catch (const SAXException& e) {
cout << "xml error: " << toNative(e.getMessage()) << "\n";
return EXIT_FAILURE;
} catch (const XMLException& e) {
cout << "xml error: " << toNative(e.getMessage()) << "\n";
return EXIT_FAILURE;
} catch (const exception& e) {
cout << e.what() << "\n";
return EXIT_FAILURE;
}
}
示例14-14 使用XercesDOMParser来验证这个animals.xml文档的DTD animals.dtd的合法性
#include <exception>
#include <iostream>// cout
#include <stdexcept> // runtime_error
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include "xerces_strings.hpp" // Example 14-4
using namespace std;
using namespace xercesc;
/*
* Define XercesInitializer as in Example 14-8
* and CircusErrorHandler as in Example 14-7
*/
int main()
{
try {
// Initialize Xerces and construct a DOM parser.
XercesInitializer init;
XercesDOMParserparser;
// Enable DTD validation
parser.setValidationScheme(XercesDOMParser::Val_Always);
// Register an error handler to receive notifications
// of schema violations
CircusErrorHandler handler;
parser.setErrorHandler(&handler);
// Parse and validate.
parser.parse("animals.xml");
} catch (const SAXException& e) {
cout << "xml error: " << toNative(e.getMessage()) << "\n";
return EXIT_FAILURE;
} catch (const XMLException& e) {
cout << "xml error: " << toNative(e.getMessage()) << "\n";
return EXIT_FAILURE;
} catch (const exception& e) {
cout << e.what() << "\n";
return EXIT_FAILURE;
}
}






