mokky14's IT diary

IT関係の仕事メモ、勉強会の感想など書いてます。

C++でXerces使ってxml解析

Xerces-C++xml解析するプログラム作ったのでメモ残しとく。


xmlのパーサはXercesを使用することにした。
(最初はlibxml2を使おうとしたけど、APIが多すぎてイヤになった)

インストは以下手順でインスト。

$  tar xvzf xerces-c-3.1.1.tar.gz 
$  cd xerces-c-3.1.1
$  ./configure
$  make
$  sudo make install

まずは写経してみる。
解析するxmlファイルはこんなやつを用意。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE infos [
		<!ELEMENT infos (info)*>
		<!ELEMENT info (id, status, datas?)>
		<!ELEMENT id (#PCDATA)>
		<!ELEMENT status (#PCDATA)>
		<!ELEMENT datas (data)*>
		<!ELEMENT data (#PCDATA)>
		<!ATTLIST data
				type CDATA #REQUIRED
				value CDATA #REQUIRED>
		]>
<infos>
	<info>
		<id>id1</id>
		<status>0</status>
		<datas>
			<data type="1" value="user@123"/>
		</datas>
	</info>
	
	<info>
		<id>id2</id>
		<status>1</status>
	</info>
	<info>
		<id>id3</id>
		<status>2</status>
		<datas></datas>
	</info>
	<info>
		<id>id4</id>
		<status>3</status>
		<datas>
			<data type="1" value="user@123"/>
			<data type="2" value="user@12345678"/>
			<data type="5" value="12345678"/>
		</datas>
	</info>
</infos>


ソースはここのやつを参考(というか丸パクリ)にして作成。
xmlからDOMを生成して頭から表示するプログラム。

#include <iostream>
using namespace std;

#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMNode.hpp>
#include <xercesc/dom/DOMText.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/sax/HandlerBase.hpp>
using namespace xercesc;

#define OK 0
#define NG 1

#define XMLFILE_PATH "sample.xml"

void writeNode(DOMNode* node);
void writeElement(DOMElement* element);
void writeText(DOMText* text);

int main(int argc, char** argv) {
	try{
		XMLPlatformUtils::Initialize();
	}
	catch(const XMLException& exp) {
		char* message = XMLString::transcode(exp.getMessage());
		cerr << "Xerces-C++ 初期化エラー" << endl;
		cerr << message << endl;
		XMLString::release(&message);
		return NG;
	}
	
	XercesDOMParser* parser = new XercesDOMParser();
	parser->setValidationScheme(XercesDOMParser::Val_Always);
	parser->setDoNamespaces(true);

	ErrorHandler* errHandler = new HandlerBase();
	parser->setErrorHandler(errHandler);

	
	try {
		const char* xmlFile = XMLFILE_PATH;
		parser->parse(xmlFile);
		DOMDocument* dom = parser->getDocument();
		writeNode(dom);
	}
	catch ( const XMLException& exp ) {
		char* message = XMLString::transcode(exp.getMessage());
		cout<< "Exception message is: \n" << message << endl;
		XMLString::release(&message);
		return NG;
	}
	catch ( const DOMException& exp ) {
		char* message = XMLString::transcode(exp.getMessage());
		cout<< "Exception message is: \n" << message << endl;
		XMLString::release(&message);
		return NG;
	}
	catch (...) {
		cout << "Unexpected Exception" << endl;
		return NG;
	}

	delete parser;
	delete errHandler;
	
	return OK;
}

void writeNode(DOMNode* node) {
	assert(node != NULL);

	switch( node->getNodeType() ) {
		case DOMNode::ELEMENT_NODE:
			writeElement(static_cast<DOMElement*>(node));
			break;

		case DOMNode::TEXT_NODE:
			writeText(static_cast<DOMText*>(node));
			break;
	}

	DOMNode* child = node->getFirstChild();
	while(child) {
		writeNode(child);
		DOMNode* next = child->getNextSibling();
		child = next;	
	}
}

void writeElement(DOMElement* element) {
	char* name = XMLString::transcode(element->getTagName());
	cout << "tag     :" << name << endl;
	XMLString::release(&name);

	DOMNamedNodeMap* map = element->getAttributes();
	for ( XMLSize_t i = 0; i < map->getLength(); i++ ) {
		DOMAttr* attr= static_cast<DOMAttr*>(map->item(i));
		char* attr_name = XMLString::transcode(attr->getName());
		char* attr_value = XMLString::transcode(attr->getValue());
		cout << attr_name << ": " << attr_value << endl;

		XMLString::release(&attr_name);
		XMLString::release(&attr_value);
	}
}

void writeText(DOMText* text) {
	XMLCh* buffer = new XMLCh[XMLString::stringLen(text->getData()) + 1];
	XMLString::copyString(buffer, text->getData());
	XMLString::trim(buffer);
	char* content = XMLString::transcode(buffer);
	delete[] buffer;

	cout << "content :" << content << endl;
	XMLString::release(&content);
}

実行結果。

tag     :infos
content :
tag     :info
content :
tag     :id
content :id1
content :
tag     :status
content :0
content :
tag     :datas
content :
tag     :data
type: 1
value: user@123
content :
content :
content :
tag     :info
content :
tag     :id
content :id2
content :
tag     :status
content :1
content :
content :
tag     :info
content :
tag     :id
content :id3
content :
tag     :status
content :2
content :
tag     :datas
content :
content :
tag     :info
content :
tag     :id
content :id4
content :
tag     :status
content :3
content :
tag     :datas
content :
tag     :data
type: 1
value: user@123
content :
tag     :data
type: 2
value: user@12345678
content :
tag     :data
type: 5
value: 12345678
content :
content :
content :

一応動いた。

最終的にやりたいのは、このDOMオブジェクトに対して、任意のtagを指定したアクセスなので、もう少し勉強してみる。