Xerces-C++ SAX2 Schema校验

来源:互联网 发布:靠谱的网络征友 编辑:程序博客网 时间:2024/05/22 15:46

  经过几天的研究,终于完成了XML的SAX2 Schema校验。

  关于什么是Schema校验,在这里就不废话了,可以去google一下。

 下面我就把整个的过程写一下。


借用网上的一些XML文件。

store.xsd文件如下:

<?xml version="1.0" encoding="UTF-8"?><!-- edited with XMLSpy v2011 (http://www.altova.com) by kevin (neuseeker) --><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">    <xs:element name="store">        <xs:annotation>            <xs:documentation>Comment describing your root element</xs:documentation>        </xs:annotation>        <xs:complexType>            <xs:sequence>                <xs:element ref="goods" maxOccurs="unbounded"/>            </xs:sequence>        </xs:complexType>    </xs:element>    <xs:element name="goods">        <xs:complexType>            <xs:sequence>                <xs:element ref="id"/>                <xs:element ref="price"/>                <xs:element ref="vendor"/>            </xs:sequence>        </xs:complexType>    </xs:element>    <xs:element name="id" type="xs:string"/>    <xs:element name="price" type="xs:double"/>    <xs:element name="vendor" type="xs:string"/></xs:schema>
test_good.xml

<?xml version="1.0" encoding="utf-8"?><store>    <goods>        <id>"0001"</id>        <price>3.50</price>        <vendor>"xxx奶粉"</vendor>    </goods>    <goods>        <id>"0002"</id>        <price>66.00</price>        <vendor>"yyy进口奶粉"</vendor>    </goods></store>

test_bad.xml

<?xml version="1.0" encoding="utf-8"?><store>    <goods>        <id>"0001"</id>        <price>3.50</price>        <vendor>"xxx奶粉"</vendor>        <name>"四路奶粉"</name>    </goods>    <goods>        <id>"0002"</id>        <price>"66.00"</price>        <vendor>"yyy进口奶粉"</vendor>    </goods></store>

以以上三个文件为例,进行验证。


代码如下:

OperContentHandler .hpp

#pragma  once#if !defined(AFX_A1CONTENTHANDLER_H__E0CFBC18_CCC1_42F3_B0A4_B03331AB9693__INCLUDED_)#define AFX_A1CONTENTHANDLER_H__E0CFBC18_CCC1_42F3_B0A4_B03331AB9693__INCLUDED_#include "stdafx.h"#include <xercesc\sax2\DefaultHandler.hpp>#include <iostream>using namespace std;class  OperContentHandler :public DefaultHandler{public:OperContentHandler();virtual ~OperContentHandler();void characters(const   XMLCh* const    chars, const XMLSize_t         length);void endElement(const XMLCh* const uri,const XMLCh* const localname,const XMLCh* const qname);virtual void startElement(const   XMLCh* const    uri,const   XMLCh* const    localname,const   XMLCh* const    qname, const Attributes&attrs);        // 继承自default Handle, 用于对错误的处理void error(const SAXParseException& exc){throw exc;}void fatalError(const SAXParseException& exc){throw exc;}void warning(const SAXParseException& exc){throw exc;}wstring goods;};#endif // !defined(AFX_A1CONTENTHANDLER_H__E0CFBC18_CCC1_42F3_B0A4_B03331AB9693__INCLUDED_)

OperContentHandler.cpp


// OperContentHandler.cpp: derived class from SAXContentHandlerImpl#include "stdafx.h"#include "OperContentHandler.hpp"//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////OperContentHandler::OperContentHandler(){}OperContentHandler::~OperContentHandler(){//object destruction is handled by the Release() impl of parent class}void OperContentHandler::startElement(const   XMLCh* const    uri,const   XMLCh* const    localname,const   XMLCh* const    qname, const Attributes&attrs){wstringsNodeName = localname;goods += sNodeName;}void OperContentHandler::endElement( const XMLCh* const uri, const XMLCh* const localname,const XMLCh* const qname ){wstringsNodeName = localname;goods += sNodeName;}void OperContentHandler::characters( const XMLCh* const chars, const XMLSize_t length ){wstring sNodeValue(chars);goods += sNodeValue;}

SAXSchema.cpp文件

// SAXSchema.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "SAX2XMLReader.hpp"#include "xercesc\sax2\XMLReaderFactory.hpp"#include "OperContentHandler.hpp"#include <stdio.h>#include <string>using namespace std;using namespace xercesc_3_1; void memcpyEx(wchar_t* wDest, int iDsize, wstring src){size_t iCpy = src.length() + 1; // '\0'size_t iMax = iDsize/sizeof(wchar_t);if (src.empty()){memset(wDest, 0, iMax);return;}if (iCpy < iMax){wmemset(wDest, 0, iMax);wmemcpy(wDest, src.c_str(), iCpy);}else{wmemset(wDest, '\0', iMax);iCpy = iMax - 1;wmemcpy(wDest, src.c_str(), iCpy);}}int _tmain(int argc, char* argv[]){wchar_t *xmlPath = L"H:\\WorkSpace\\MarkupTest\\MarkupTest\\test_bad.xml";wchar_t *sxsdPath = L"H:\\WorkSpace\\MarkupTest\\MarkupTest\\store.xsd";OperContentHandler handler;wstring xsdPath(sxsdPath);try{XMLPlatformUtils::Initialize();}catch (...) {return 1;}SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();parser->setFeature(XMLUni::fgSAX2CoreValidation, true);parser->setFeature(XMLUni::fgXercesSchema, true);parser->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);parser->setFeature(XMLUni::fgXercesContinueAfterFatalError, false);// 当Schema存在命名空间时,使用此部分;其中L"http://www.iec.ch/61850/2003/SCL "为我在试验时的一个命名空间        //wstring xsd =  L"http://www.iec.ch/61850/2003/SCL " + xsdPath;//wchar_t xsdCh[400];//memcpyEx(xsdCh, sizeof(xsdCh), xsd);//parser->setProperty(XMLUni::fgXercesSchemaExternalSchemaLocation, xsdCh);                // 当Schema不存在命名空间时,使用这个方法;在上述的XML中应该使用这个方法来设置模板文件parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, sxsdPath);        parser->setContentHandler(&handler);parser->setErrorHandler(&handler);try{parser->parse(xmlPath); }catch (const SAXParseException& toCatch) { int iCol = toCatch.getColumnNumber();int iRow = toCatch.getLineNumber();wchar_t cCol[10], cRow[10]; _itow(iCol, cCol, 10); _itow(iRow, cRow, 10);wstring sCol(cCol);wstring sRow(cRow);wstring sMes(toCatch.getMessage());                // 此处将展示错误信息                wstring wValue = L"行:" + sRow + L",列:" + sCol+ L"  " + sMes;return 0; }catch (const OutOfMemoryException &ome){wstring sMes(ome.getMessage());return false; }catch (const XMLException &xe){wstring sMes(xe.getMessage());return false; }delete parser;XMLPlatformUtils::Terminate();return 0;}

当进行校验完成后,在wValue的值为:行:7,列:9  no declaration found for element 'name'


上面就是整个Schema校验的校验过程,注意点主要为一下:

一,

在上述的OperContentHandler中,我们重写了继承自DefaultHandler的三个错误处理方法。如果不重写这些方法,OperContentHandler则只是处理了解析过程中和文档内容相关的事件。如果不注册一个错误处理器来处理的话,那么错误事件将不会被报告,而且解析器会出现不可预知的行为。在解析过程中产生的错误被分成了3类,它们分别是warning,error,以及fatalerror,也就是说在ErrorHandler中有这么三个相应的方法来处理这些错误事件。

二,

通过设置fgXercesSchemaExternalNoNameSpaceSchemaLocation或者fgXercesSchemaExternalSchemaLocation属性来设置XSD文件;之前一直以为可以通过loadGrammar()来进行XSD的设置,但是总是不行,可能是理解不到位,不会使用。所以改成了设置属性这种方法。


参考文献:

1,http://www.cnblogs.com/kevin_neu/archive/2013/04/16/3003514.html

2,http://www.codeproject.com/Articles/11085/Parsing-XML-using-a-C-wrapper-for-SAX2

3,http://www.ibm.com/developerworks/cn/xml/x-xsdxerc.html

4,http://xerces.apache.org/xerces-c/program-sax2-3.html

5,https://www.ibm.com/developerworks/cn/xml/x-saxhandle/