/*
* $Id: XMLTool.cpp,v 1.3 2006/06/20 10:11:06 ozawa Exp $
*
* Copyright 2005- ONGS Inc. All rights reserved.
*
* author: Masanori OZAWA (ozawa@ongs.co.jp)
* version: $Revision: 1.3 $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY ONGS INC ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ONGS INC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the ONGS Inc.
*
*/
#include "xdtp.h"
#include "XMLTool.h"
#include "Utilities.h"
#include "libxml/xmlmemory.h"
#include "libxml/xmlIO.h"
using namespace XDTP;
XMLTool::XMLTool()
{
static bool init = false;
if (!init) {
xmlInitParser();
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
init = true;
}
}
XMLTool::~XMLTool()
{
}
/**
* 複数階層に跨るElementを一度に生成します。
* 既存のElementが存在する場合は、存在しないElementのみを生成します。
*
* @param aDocument
* 生成対象のDOM オブジェクト
* @param aXPath
* 複数階層に跨るElementを識別するXPath。
* 1つの階層に複数のElementを指定するようなことはできません。(書式: /e1/e2/e3/e4 )
* @return 作成に成功したときは最下層の Element。失敗したときは null。
*/
xmlNodePtr XMLTool::createElements(xmlDocPtr aDocument, const Glib::ustring& aXPath)
{
int count = 0;
gchar **tokens = g_strsplit(aXPath.c_str(), "/", 0);
xmlNodePtr node = NULL;
xmlNodePtr parent = xmlDocGetRootElement(aDocument);
if (!tokens) return NULL;
if (!tokens[0] || !tokens[1]) {
g_strfreev(tokens);
return NULL;
}
if (xmlStrcmp(parent->name, (const xmlChar *)tokens[1])) {
g_strfreev(tokens);
return NULL;
}
node = parent->xmlChildrenNode;
for (count = 2; tokens[count]; count++) {
while (node && xmlStrcmp(node->name, (const xmlChar *)tokens[count])) {
node = node->next;
}
if (node) {
parent = node;
node = parent->xmlChildrenNode;
}
else {
// 新規に構築
node = xmlNewDocNode(aDocument, NULL, (xmlChar*)tokens[count], NULL);
xmlAddChild(parent, node);
parent = node;
node = NULL;
}
}
if (tokens[count]) {
parent = NULL;
}
g_strfreev(tokens);
return parent;
}
/**
* XMLファイルのエンコーディングを取得します。
*
* @param aFile XMLファイル名
* @return エンコーディング
*/
std::string XMLTool::getEncoding(const Glib::ustring& aFile)
{
std::string result;
// XML文章のエンコードを取得する
try {
Glib::ustring line;
Glib::ustring::size_type pos;
Glib::RefPtr<Glib::IOChannel> ioc =
Glib::IOChannel::create_from_file(aFile.c_str(), "r");
ioc->set_encoding("ASCII");
while (ioc->read_line(line) == Glib::IO_STATUS_NORMAL) {
if (!line.empty()) {
line = Utilities::strTrim(line);
line = line.lowercase();
if ("<?" == line.substr(0, 2)) {
pos = line.find("encoding=\"");
if (Glib::ustring::npos != pos) {
line = line.substr(pos +10);
pos = line.find("\"");
if (Glib::ustring::npos != pos) {
result = line.substr(0, pos);
}
}
}
break;
}
}
ioc->close();
}
catch (Glib::Error error) {
std::string msg = Glib::locale_from_utf8(error.what());
fprintf(stderr, "%s: %s" LINE_SEP, APP_NAME, msg.c_str());
}
catch (...) {
fprintf(stderr, "%s: XMLTool: Unable to read the XML file. (%s)" LINE_SEP,
APP_NAME, aFile.c_str());
}
return result;
}
/**
* Nodeからの相対XPath指定で得られるNodeの一覧を取得します。
*
* @param aNode
* 探索元のNode
* @param aXPath
* Nodeからの相対XPath
* @return 取得したNodeの一覧を保持するオブジェクト。
* 不要になった段階で、xmlXPathFreeObjectする必要があります。
*/
xmlXPathObjectPtr XMLTool::getNodeList(xmlNodePtr aNode, const Glib::ustring& aXPath)
{
if (!aNode) return NULL;
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(aNode->doc);
xmlXPathObjectPtr xpathObj;
if (!xpathCtx) return NULL;
xpathCtx->node = aNode; // set the current node
xpathObj = xmlXPathEvalExpression((const xmlChar*)aXPath.c_str(), xpathCtx);
xmlXPathFreeContext(xpathCtx);
if (!xpathObj) {
return NULL;
}
if (xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) {
xmlXPathFreeObject(xpathObj);
return NULL;
}
return xpathObj;
}
/**
* Nodeの直下に存在するTextを取得します。
*
* @param aNode
* Textを含んだNode
* @return 取得したTextの文字列。Textが存在しない場合は空文字列。
*/
Glib::ustring XMLTool::getText(xmlNodePtr aNode)
{
Glib::ustring result;
xmlChar *text = xmlNodeListGetString(aNode->doc, aNode->xmlChildrenNode, 1);
if (text) {
result = (char*)text;
xmlFree(text);
}
return result;
}
/**
* NodeがAttributeかチェックします。
*
* @param aNode
* チェック対象のNode
* @return Attributeの場合は true
*/
bool XMLTool::isAttribute(xmlNodePtr aNode)
{
return (XML_ATTRIBUTE_NODE == aNode->type);
}
/**
* NodeがCommentかチェックします。
*
* @param aNode
* チェック対象のNode
* @return Commentの場合は true
*/
bool XMLTool::isComment(xmlNodePtr aNode)
{
return (XML_COMMENT_NODE == aNode->type);
}
/**
* NodeがElementかチェックします。
*
* @param aNode
* チェック対象のNode
* @return Elementの場合は true
*/
bool XMLTool::isElement(xmlNodePtr aNode)
{
return (XML_ELEMENT_NODE == aNode->type);
}
/**
* NodeがTextかチェックします。
*
* @param aNode
* チェック対象のNode
* @return Textの場合は true
*/
bool XMLTool::isText(xmlNodePtr aNode)
{
return (XML_TEXT_NODE == aNode->type);
}
/**
* Nodeの直下にTextを設定します。
*
* @param aNode
* Textを設定するNode
* @param aText
* 設定するText
* @return 設定に成功した場合は true
*/
bool XMLTool::setText(xmlNodePtr aNode, const Glib::ustring& aText)
{
bool result = false;
xmlNodePtr node = aNode->children;
while (node) {
if (isText(node)) {
xmlNodeSetContent(node, (const xmlChar *)aText.c_str());
result = true;
break;
}
node = node->next;
}
if (!result) {
// Textノードを新規に構築
node = xmlNewDocText(aNode->doc, (xmlChar*)aText.c_str());
result = (xmlAddChild(aNode, node) ? true : false);
}
return result;
}
/**
* DOMドキュメントを、XSLTを用いて変換します。
*
* @param aDocument
* 変換元のDOMドキュメント
* @param aXSLFile
* XSLファイル
* @return 変換後のDOMドキュメント。不要になった段階でxmlFreeDocする必要があります。
*/
xmlDocPtr XMLTool::transform(xmlDocPtr aDocument, const Glib::ustring& aXSLFile)
{
xsltStylesheetPtr xsl;
xmlDocPtr result;
xsl = xsltParseStylesheetFile((const xmlChar *)aXSLFile.c_str());
result = transform(aDocument, xsl);
xsltFreeStylesheet(xsl);
return result;
}
/**
* DOMドキュメントを、XSLTを用いて変換します。
*
* @param aDocument
* 変換元のDOMドキュメント
* @param aXSL
* XSLオブジェクト
* @return 変換後のDOMドキュメント。不要になった段階でxmlFreeDocする必要があります。
*/
xmlDocPtr XMLTool::transform(xmlDocPtr aDocument, xsltStylesheetPtr aXSL)
{
return xsltApplyStylesheet(aXSL, aDocument, NULL);
}
syntax highlighted by Code2HTML, v. 0.9.1