/** @file Parser: @b xdoc parser class. Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) Author: Alexander Petrosyan (http://design.ru/paf) $Id: xdoc.C,v 1.4 2001/09/27 07:54:58 parser Exp $ */ #include "classes.h" #ifdef XML #include "pa_request.h" #include "pa_vxdoc.h" #include "pa_xslt_stylesheet_manager.h" #include "pa_stylesheet_connection.h" #include "pa_vfile.h" #include "xnode.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // defines #define XDOC_CLASS_NAME "xdoc" #define XDOC_OUTPUT_METHOD_OPTION_NAME "method" #define XDOC_OUTPUT_METHOD_OPTION_VALUE_XML "xml" #define XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML "html" #define XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT "text" #define XDOC_OUTPUT_ENCODING_OPTION_NAME "encoding" #define XDOC_OUTPUT_DEFAULT_INDENT 4 // class class MXdoc : public MXnode { public: // VStateless_class Value *create_new_value(Pool& pool) { return new(pool) VXdoc(pool); } public: MXdoc(Pool& pool); public: // Methoded bool used_directly() { return true; } }; // methods class ParserStringXalanOutputStream: public XalanOutputStream { public: explicit ParserStringXalanOutputStream(String& astring) : fstring(astring) {} protected: // XalanOutputStream virtual void writeData(const char *theBuffer, unsigned long theBufferLength) { char *copy=(char *)fstring.malloc((size_t)theBufferLength); memcpy(copy, theBuffer, (size_t)theBufferLength); fstring.APPEND_CLEAN(copy, (size_t)theBufferLength, "xdoc", 0); } virtual void doFlush() {} private: String& fstring; }; static void create_optioned_listener( const char *& content_type, const char *& charset, FormatterListener *& listener, Pool& pool, const String& method_name, MethodParams *params, int index, Writer& writer) { // default encoding from pool const String *scharset=&pool.get_charset(); const String *method=0; XalanDOMString xalan_encoding; if(params->size()>index) { Value& voptions=params->as_no_junction(index, "options must not be code"); if(voptions.is_defined()) { if(Hash *options=voptions.get_hash()) { // $.method[xml|html|text] if(Value *vmethod=static_cast(options->get(*new(pool) String(pool, XDOC_OUTPUT_METHOD_OPTION_NAME)))) method=&vmethod->as_string(); // $.encoding[windows-1251|...] if(Value *vencoding=static_cast(options->get(*new(pool) String(pool, XDOC_OUTPUT_ENCODING_OPTION_NAME)))) { scharset=&vencoding->as_string(); } } else PTHROW(0, 0, &method_name, "options must be hash"); } } xalan_encoding.append(charset=scharset->cstr()); if(!method/*default='xml'*/ || *method == XDOC_OUTPUT_METHOD_OPTION_VALUE_XML) { content_type="text/xml"; listener=new FormatterToXML(writer, XalanDOMString(), // version true, // doIndent XDOC_OUTPUT_DEFAULT_INDENT, // indent xalan_encoding // encoding ); } else if(*method == XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML) { content_type="text/html"; listener=new FormatterToHTML(writer, xalan_encoding, // encoding XalanDOMString(), // mediaType XalanDOMString(), // doctypeSystem; String to be printed at the top of the document XalanDOMString(), // doctypePublic true, // doIndent XDOC_OUTPUT_DEFAULT_INDENT // indent ); } else if(*method == XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT) { content_type="text/plain"; listener=new FormatterToText(writer, xalan_encoding // encoding ); } else PTHROW(0, 0, method, XDOC_OUTPUT_METHOD_OPTION_NAME " option is invalid; valid methods are: " "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_XML "', " "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML "', " "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT "'"); // never reached } static void _save(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXnode& vnode=*static_cast(r.self); // filespec const String& file_name=params->as_string(0, "file name must not be code"); const char *filespec=r.absolute(file_name).cstr(String::UL_FILE_SPEC); // node XalanNode& node=vnode.get_node(pool, &method_name); try { XalanFileOutputStream stream(XalanDOMString(filespec, strlen(filespec))); XalanOutputStreamPrintWriter writer(stream); const char *content_type, *charset; FormatterListener *formatterListener; create_optioned_listener(content_type, charset, formatterListener, pool, method_name, params, 1, writer); FormatterTreeWalker treeWalker(*formatterListener); treeWalker.traverse(&node); // Walk that node and produce the XML... } catch(const XSLException& e) { r._throw(&method_name, e); } } static void _string(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXnode& vnode=*static_cast(r.self); // node XalanNode& node=vnode.get_node(pool, &method_name); try { String parserString=*new(pool) String(pool); ParserStringXalanOutputStream stream(parserString); XalanOutputStreamPrintWriter writer(stream); const char *content_type, *charset; FormatterListener *formatterListener; create_optioned_listener(content_type, charset, formatterListener, pool, method_name, params, 0, writer); FormatterTreeWalker treeWalker(*formatterListener); treeWalker.traverse(&node); // Walk that node and produce the XML... // write out result r.write_no_lang(parserString); } catch(const XSLException& e) { r._throw(&method_name, e); } } static void _file(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXnode& vnode=*static_cast(r.self); // node XalanNode& node=vnode.get_node(pool, &method_name); try { String& parserString=*new(pool) String(pool); ParserStringXalanOutputStream stream(parserString); XalanOutputStreamPrintWriter writer(stream); const char *content_type, *charset; FormatterListener *formatterListener; create_optioned_listener(content_type, charset, formatterListener, pool, method_name, params, 0, writer); FormatterTreeWalker treeWalker(*formatterListener); treeWalker.traverse(&node); // Walk that node and produce the XML... // write out result VFile& vfile=*new(pool) VFile(pool); const char *cstr=parserString.cstr(); String *scontent_type=new(pool) String(pool, content_type); Value *vcontent_type; if(charset) { VHash *vhcontent_type=new(pool) VHash(pool); vhcontent_type->hash().put(*value_name, new(pool) VString(*scontent_type)); String *scharset=new(pool) String(pool, charset); vhcontent_type->hash().put(*new(pool) String(pool, "charset"), new(pool) VString(*scharset)); vcontent_type=vhcontent_type; } else vcontent_type=new(pool) VString(*scontent_type); vfile.set(false/*tainted*/, cstr, strlen(cstr), 0/*file_name*/, vcontent_type); r.write_no_lang(vfile); } catch(const XSLException& e) { r._throw(&method_name, e); } } static void _set(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXdoc& vdom=*static_cast(r.self); Value& vxml=params->as_junction(0, "xml must be code"); Temp_lang temp_lang(r, String::UL_XML); const String& xml=r.process(vxml).as_string(); std::istrstream stream(xml.cstr()); const XalanParsedSource* parsedSource; int error=vdom.transformer().parseSource(&stream, parsedSource); if(error) PTHROW(0, 0, &method_name, vdom.transformer().getLastError()); // replace any previous parsed source vdom.set_parsed_source(*parsedSource); } static void _load(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXdoc& vdom=*static_cast(r.self); // filespec const String& file_name=params->as_string(0, "file name must not be code"); const char *filespec=r.absolute(file_name).cstr(String::UL_FILE_SPEC); const XalanParsedSource* parsedSource; int error=vdom.transformer().parseSource(filespec, parsedSource); if(error) PTHROW(0, 0, &file_name, vdom.transformer().getLastError()); // replace any previous parsed source vdom.set_parsed_source(*parsedSource); } static void add_xslt_param(const Hash::Key& aattribute, Hash::Val *ameaning, void *info) { XalanTransformer& transformer=*static_cast(info); const char *attribute_cstr=aattribute.cstr(); const char *meaning_cstr=static_cast(ameaning)->as_string().cstr(); transformer.setStylesheetParam( XalanDOMString(attribute_cstr), XalanDOMString(meaning_cstr)); } static void _xslt(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXdoc& vdom=*static_cast(r.self); // params if(params->size()>1) { Value& vparams=params->as_no_junction(1, "transform parameters parameter must not be code"); if(vparams.is_defined()) if(Hash *params=vparams.get_hash()) params->for_each(add_xslt_param, &vdom.transformer()); else PTHROW(0, 0, &method_name, "transform parameters parameter must be hash"); } // source const XalanParsedSource &parsed_source=vdom.get_parsed_source(pool, &method_name); // stylesheet const String& stylesheet_file_name=params->as_string(0, "file name must not be code"); const String& stylesheet_filespec=r.absolute(stylesheet_file_name); //_asm int 3; Stylesheet_connection& connection=XSLT_stylesheet_manager->get_connection(stylesheet_filespec); // target XalanDocument* target=vdom.parser_liaison().createDocument(); XSLTResultTarget domResultTarget(target); // transform int error=vdom.transformer().transform( parsed_source, &connection.stylesheet(), domResultTarget); connection.close(); if(error) PTHROW(0, 0, &stylesheet_file_name, vdom.transformer().getLastError()); // write out result VXdoc& result=*new(pool) VXdoc(pool); result.set_document(*target); r.write_no_lang(result); } static void _getElementById(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXdoc& vdoc=*static_cast(r.self); // elementId const char *elementId=params->as_string(0, "elementID must not be code").cstr(String::UL_AS_IS); if(XalanElement *element= vdoc.get_document(pool, &method_name).getElementById(XalanDOMString(elementId))) { // write out result VXnode& result=*new(pool) VXnode(pool, element); r.write_no_lang(result); } } /* static void _getElementsByTagName(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXdoc& vdoc=*static_cast(r.self); // tagname const char *tagname=params->as_string(0, "tagname must not be code").cstr(String::UL_AS_IS); VHash& result=*new(pool) VHash(pool); if(const XalanNodeList *nodes= vdoc.get_document(pool, &method_name).getElementsByTagName(XalanDOMString(tagname))) { for(int i=0; igetLength(); i++) { String& skey=*new(pool) String(pool); { char *buf=(char *)pool.malloc(MAX_NUMBER); snprintf(buf, MAX_NUMBER, "%d", i); skey << buf; } result.hash().put(skey, new(pool) VXnode(pool, nodes->item(i))); } } // write out result r.write_no_lang(result); } static void _getElementsByTagNameNS(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); VXdoc& vdoc=*static_cast(r.self); // namespaceURI;localName const char *namespaceURI=params->as_string(0, "namespaceURI must not be code").cstr(String::UL_AS_IS); const char *localName=params->as_string(0, "localName must not be code").cstr(String::UL_AS_IS); VHash& result=*new(pool) VHash(pool); if(const XalanNodeList *nodes= vdoc.get_document(pool, &method_name).getElementsByTagNameNS( XalanDOMString(namespaceURI), XalanDOMString(localName))) { for(int i=0; igetLength(); i++) { String& skey=*new(pool) String(pool); { char *buf=(char *)pool.malloc(MAX_NUMBER); snprintf(buf, MAX_NUMBER, "%d", i); skey << buf; } result.hash().put(skey, new(pool) VXnode(pool, nodes->item(i))); } } // write out result r.write_no_lang(result); } */ // constructor MXdoc::MXdoc(Pool& apool) : MXnode(apool) { set_name(*NEW String(pool(), XDOC_CLASS_NAME)); // ^xdoc.save[some.xml] // ^xdoc.save[some.xml;options hash] add_native_method("save", Method::CT_DYNAMIC, _save, 1, 2); // ^xdoc.string[] // ^xdoc.string[options hash] add_native_method("string", Method::CT_DYNAMIC, _string, 0, 1); // ^xdoc.file[] file with "" // ^xdoc.file[options hash] file with "" add_native_method("file", Method::CT_DYNAMIC, _file, 0, 1); // ^xdoc::set[xml] add_native_method("set", Method::CT_DYNAMIC, _set, 1, 1); // ^xdoc::load[some.xml] add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1); // ^xdoc.xslt[stylesheet file_name] // ^xdoc.xslt[stylesheet file_name;params hash] add_native_method("xslt", Method::CT_DYNAMIC, _xslt, 1, 2); // ^xdoc.getElementById[elementId] add_native_method("getElementById", Method::CT_DYNAMIC, _getElementById, 1, 1); /* // ^xdoc.getElementsByTagName[tagname] add_native_method("getElementsByTagName", Method::CT_DYNAMIC, _getElementsByTagName, 1, 1); // ^xdoc.getElementsByTagNameNS[namespaceURI;localName] = array of nodes add_native_method("getElementsByTagNameNS", Method::CT_DYNAMIC, _getElementsByTagNameNS, 2, 2); */ } // global variable Methoded *Xdoc_class; // creator #endif Methoded *MXdoc_create(Pool& pool) { return #ifdef XML Xdoc_class=new(pool) MXdoc(pool); #else 0 #endif ; }