/*
* $Id: GLSDDocumentModule.cpp,v 1.18 2006/06/29 07:26:42 ozawa Exp $
*
* Copyright 2005- ONGS Inc. All rights reserved.
*
* author: Masanori OZAWA (ozawa@ongs.co.jp)
* version: $Revision: 1.18 $
*
* 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 "modules/GLSDDocumentModule.h"
#include "URLTool.h"
#include "xmlloader.h"
#include "XMLTool.h"
#include "modules/imports/ImportImage.h"
#include "modules/imports/ImportTextCSV.h"
#include "modules/imports/ImportTextCommandPrompt.h"
#include "modules/imports/ImportTextPlain.h"
#include "modules/imports/ImportTextSourcecode.h"
#include "modules/imports/ImportTextXML.h"
using namespace XDTP;
GLSDDocumentModule::GLSDDocumentModule()
{
#ifndef WITHOUT_GDK
m_ImportModules.push_back(new ImportImage());
#endif
m_ImportModules.push_back(new ImportTextCSV());
m_ImportModules.push_back(new ImportTextCommandPrompt());
m_ImportModules.push_back(new ImportTextPlain());
m_ImportModules.push_back(new ImportTextSourcecode());
m_ImportModules.push_back(new ImportTextXML());
}
GLSDDocumentModule::~GLSDDocumentModule()
{
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
for (; iter != end; iter++) {
delete (*iter);
}
m_ImportModules.clear();
}
/**
* 処理を開始する前に出力形式を設定します。
*
* @param aType 出力形式
*/
void GLSDDocumentModule::setOutputType(const Glib::ustring& aType)
{
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.setOutputType(aType);
for (; iter != end; iter++) {
(*iter)->setOutputType(aType);
}
}
/**
* 処理を開始する前にオプションを設定します。
*
* @param anOptions オプション
*/
void GLSDDocumentModule::setOption(const StringList& anOptions)
{
bool overwrite = false;
Glib::ustring url;
StringList::const_iterator striter = anOptions.begin();
StringList::const_iterator strend = anOptions.end();
m_AliasMap.clear();
for (; striter != strend; striter++) {
url.clear();
if (0 == strncasecmp(striter->c_str(), "alias_file=", 11)) {
url = striter->substr(11);
if (0 < url.length()) {
if (Glib::path_is_absolute(url)) {
url = "file:" + url;
}
else {
// 相対パスの場合は、カレントディレクトリからの相対とみなす。
url = "file:" + Glib::build_filename(Glib::get_current_dir(), url);
}
overwrite = true;
}
}
else if (0 == strncasecmp(striter->c_str(), "alias_url=", 10)) {
url = striter->substr(10);
overwrite = false;
}
if (!url.empty()) {
if (!addAliasMap(url, overwrite)) {
THROW("Unable to parse the alias file. (" + url + ")");
}
}
}
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.setOption(anOptions);
for (; iter != end; iter++) {
(*iter)->setOption(anOptions);
}
}
/**
* 処理を開始する前に出力ファイル名を設定します。
*
* @param anOutputFile 出力ファイル名
*/
void GLSDDocumentModule::setOutputFile(const Glib::ustring& anOutputFile)
{
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.setOutputFile(anOutputFile);
for (; iter != end; iter++) {
(*iter)->setOutputFile(anOutputFile);
}
}
/**
* 処理を開始する前に変換元XMLファイル名を設定します。
*
* @param aXMLFile 変換元XMLファイル名
*/
void GLSDDocumentModule::setXMLFile(const Glib::ustring& aXMLFile)
{
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.setXMLFile(aXMLFile);
for (; iter != end; iter++) {
(*iter)->setXMLFile(aXMLFile);
}
}
/**
* 入力ファイルのエンコードを指定します。
* XMLファイルはこの限りではありません。
*
* @param anInputEncoding 入力ファイルのエンコード
*/
void GLSDDocumentModule::setInputEncoding(const Glib::ustring& anInputEncoding)
{
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.setInputEncoding(anInputEncoding);
for (; iter != end; iter++) {
(*iter)->setInputEncoding(anInputEncoding);
}
}
/**
* 出力ファイルのエンコードを指定します。
*
* @param anOutputEncoding 出力ファイルのエンコード
*/
void GLSDDocumentModule::setOutputEncoding(const Glib::ustring& anOutputEncoding)
{
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.setOutputEncoding(anOutputEncoding);
for (; iter != end; iter++) {
(*iter)->setOutputEncoding(anOutputEncoding);
}
}
/**
* 現在のXDTPTransformモジュールを指定します。
*
* @param aXDTPTransform 現在のXDTPTransformモジュール
*/
void GLSDDocumentModule::setXDTPTransform(const XDTPTransform *aXDTPTransform)
{
XDTPModuleAdapter::setXDTPTransform(aXDTPTransform);
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.setXDTPTransform(aXDTPTransform);
for (; iter != end; iter++) {
(*iter)->setXDTPTransform(aXDTPTransform);
}
}
/**
* ファイルをparseする直前に呼び出されます。
*
* @param aFile parse対象のファイル名
*/
void GLSDDocumentModule::treatPreFile(const Glib::ustring& aFile)
{
// XMLファイルのエンコーディングを解析
XMLTool tool;
std::string xmlencoding = tool.getEncoding(aFile);
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.setXMLEncoding(xmlencoding);
m_ImportTextGLSD.treatPreFile(aFile);
for (; iter != end; iter++) {
(*iter)->setXMLEncoding(xmlencoding);
(*iter)->treatPreFile(aFile);
}
}
/**
* parseしたXML文章をXSL変換する直前に呼び出されます。
*
* @param aDocument XML文章
*/
void GLSDDocumentModule::treatPreDocument(xmlDocPtr aDocument)
{
// text/glsd-* のインポート処理のみ alias タグの置換処理に優先します。
m_ImportTextGLSD.treatPreDocument(aDocument);
// alias タグの置換処理
if (!replaceAllAlias(aDocument)) {
THROW("Unable to replace an alias.");
}
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
for (; iter != end; iter++) {
(*iter)->treatPreDocument(aDocument);
}
}
/**
* XSL変換後のXML文章を保存する直前に呼び出されます。
*
* @param aDocument XML文章
*/
void GLSDDocumentModule::treatPostDocument(xmlDocPtr aDocument)
{
normalizeImport(aDocument);
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.treatPostDocument(aDocument);
for (; iter != end; iter++) {
(*iter)->treatPostDocument(aDocument);
}
}
/**
* XML文章を保存した直後に呼び出されます。
*
* @param aFile 保存したファイル名
*/
void GLSDDocumentModule::treatPostFile(const Glib::ustring& aFile)
{
// import モジュール処理
GLSDImportModuleList::iterator iter = m_ImportModules.begin();
GLSDImportModuleList::iterator end = m_ImportModules.end();
m_ImportTextGLSD.treatPostFile(aFile);
for (; iter != end; iter++) {
(*iter)->treatPostFile(aFile);
}
}
/**
* importタグを標準化します。
* 主に以下の処理を行います。<br>
* <ul>
* <li>importタグの前後の不要なpタグを削除します。
* <li>importタグへのアンカーを作成します。
* </ul>
*
* @param aDocument
* 変換対象DOMドキュメント
*/
void GLSDDocumentModule::normalizeImport(xmlDocPtr aDocument)
{
int count;
XMLTool tool;
xmlNodePtr node;
xmlNodePtr test;
xmlNodeSetPtr nodes;
xmlXPathObjectPtr obj = tool.getNodeList(xmlDocGetRootElement(aDocument), "//import");
const char *id;
if (obj) {
nodes = obj->nodesetval;
for (count = 0; count < nodes->nodeNr; count++) {
node = nodes->nodeTab[count];
// importがp要素で直接囲まれているかチェックする。
// これは、importが非構造モジュール要素であるため
// 必然的に発生してしまうことが多い。
if (node->parent && xmlStrcmp(node->parent->name, (const xmlChar*)"p") == 0) {
for (test = node->prev; test; test = test->prev) {
if (tool.isElement(test)) break;
}
if (!test) {
for (test = node->next; test; test = test->next) {
if (tool.isElement(test)) break;
}
if (!test) {
// p要素で囲む必要がないため削除する。
xmlFreeNode(xmlReplaceNode(node->parent, node));
}
}
}
}
// id属性を a タグで置き換える
for (count = 0; count < nodes->nodeNr; count++) {
node = nodes->nodeTab[count];
id = (const char*)xmlGetProp(node, (const xmlChar*)"id");
if (id) {
if (0 < strlen(id)) {
test = xmlNewNode(NULL, (const xmlChar*)"a");
xmlSetProp(test, (const xmlChar*)"name", (const xmlChar*)id);
if (!xmlAddPrevSibling(node, test)) {
// 構造上起り得ないエラー(メモリ不足?)
xmlFreeNode(test);
xmlXPathFreeObject(obj);
THROW("Unable to add element.");
}
/**
* 構造に影響が出るので、コメントアウト。 2005/09/30 ozawa
// <a/>の直後に改行を入れる。
xmlAddNextSibling(test, xmlNewText((const xmlChar*)LINE_SEP));
*/
}
xmlFree((xmlChar*)id);
}
}
xmlXPathFreeObject(obj);
}
}
/**
* alias 置換マップを構築します。
*
* @param aURL
* alias置換マップファイルへのURL
* @param anOverWrite
* alias置換マップに同じキーが登録されていた場合に、
* 値を上書きする場合は true を指定します。
* @return 構築に成功した場合は true を指定します。
*/
bool GLSDDocumentModule::addAliasMap(const Glib::ustring& aURL, bool anOverWrite)
{
int len;
char *buf;
xmlDocPtr doc;
if (!URLTool::getResource(aURL, &buf, &len)) {
#ifdef DEBUG
fprintf(stderr, "%s: error: Unable to get the resource. (%s)" LINE_SEP, APP_NAME, aURL.c_str());
#endif
return false;
}
doc = XMLLoader::loadMem(buf, len);
free(buf);
if (!doc) {
#ifdef DEBUG
fprintf(stderr, "%s: error: Unable to parse the resource. (%s)" LINE_SEP, APP_NAME, aURL.c_str());
#endif
return false;
}
bool bSuccess = true;
bool keyset, valueset;
int count;
Glib::ustring key;
Glib::ustring value;
XMLTool tool;
xmlNodePtr node;
xmlNodePtr child;
xmlNodeSetPtr nodes;
xmlXPathObjectPtr obj = tool.getNodeList(xmlDocGetRootElement(doc), "/aliases/alias");
if (obj) {
nodes = obj->nodesetval;
for (count = 0; bSuccess && count < nodes->nodeNr; count++) {
node = nodes->nodeTab[count];
child = node->children;
key.clear();
value.clear();
keyset = valueset = false;
for (; (!keyset || !valueset) && child; child = child->next) {
if (0 == strcmp((const char*)child->name, "key")) {
key = tool.getText(child);
keyset = true;
}
else if (0 == strcmp((const char*)child->name, "value")) {
value = tool.getText(child);
valueset = true;
}
}
if (!keyset || !valueset) {
if (!keyset) fprintf(stderr, "%s: error: alias has no key. (value=%s)" LINE_SEP, APP_NAME, value.c_str());
if (!valueset) fprintf(stderr, "%s: error: alias has no value. (key=%s)" LINE_SEP, APP_NAME, key.c_str());
bSuccess = false;
}
else {
if (anOverWrite || 0 == m_AliasMap.count(key)) {
m_AliasMap[key] = value;
}
}
}
xmlXPathFreeObject(obj);
}
xmlFreeDoc(doc);
return bSuccess;
}
/**
* alias の置換処理を行います。
*
* @param aDocument
* 変換対象DOMドキュメント
* @return 置換に成功した場合は true を戻します。
*/
bool GLSDDocumentModule::replaceAllAlias(xmlDocPtr aDocument)
{
bool bSuccess = true;
int count;
Glib::ustring key;
Glib::ustring value;
String2StringMap::iterator iter;
XMLTool tool;
xmlNodePtr node;
xmlNodeSetPtr nodes;
xmlXPathObjectPtr obj = tool.getNodeList(xmlDocGetRootElement(aDocument), "//p/alias");
if (obj) {
nodes = obj->nodesetval;
for (count = 0; bSuccess && count < nodes->nodeNr; count++) {
node = nodes->nodeTab[count];
key = tool.getText(node);
if (0 >= key.length()) {
fprintf(stderr, "%s: error: alias has zero length keyword." LINE_SEP, APP_NAME);
bSuccess = false;
break;
}
iter = m_AliasMap.find(key);
if (iter != m_AliasMap.end()) {
value = iter->second;
}
else {
#if 1
// 置換対象が見付からない場合はキーワードを置換文字列とする。
value = key;
#else
// 置換対象が見付からない場合に、警告を表示して alias 全体を削除。
fprintf(stderr, "%s: warning: Unable to find the value of the alias. (%s)" LINE_SEP,
APP_NAME, key.c_str());
xmlUnlinkNode(node);
xmlFreeNode(node);
continue;
#endif
}
xmlFreeNode(xmlReplaceNode(node, xmlNewText((const xmlChar*)value.c_str())));
}
xmlXPathFreeObject(obj);
}
return bSuccess;
}
syntax highlighted by Code2HTML, v. 0.9.1