/* * $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タグを標準化します。 * 主に以下の処理を行います。
* * * @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 // の直後に改行を入れる。 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; }