/** @file Parser: @b xdoc parser class. Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ #include "classes.h" #ifdef XML static const char* IDENT_XDOC_C="$Date: 2003/03/07 11:16:44 $"; #include "pa_vmethod_frame.h" #include "pa_stylesheet_connection.h" #include "pa_request.h" #include "pa_vxdoc.h" #include "pa_charset.h" #include "pa_vfile.h" #include "xnode.h" #include "gdome.h" #include "libxml/tree.h" extern "C" { #include "gdomecore/gdome-xml-node.h" #include "gdomecore/gdome-xml-document.h" }; #include "libxslt/xsltInternals.h" #include "libxslt/transform.h" #include "libxslt/xsltutils.h" #include "libxslt/variables.h" // 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" // class class MXdoc: public MXnode { public: // VStateless_class ValuePtr create_new_value() { return ValuePtr(new VXdoc(0, 0, 0)); } public: MXdoc(); public: // Methoded void configure_admin(Request& r); }; // global variable DECLARE_CLASS_VAR(xdoc, new MXdoc, 0); // helper classes class xmlOutputBuffer_auto_ptr { public: explicit xmlOutputBuffer_auto_ptr(xmlOutputBuffer *_APtr = 0) : _Owns(_APtr != 0), _Ptr(_APtr) {} xmlOutputBuffer_auto_ptr(const xmlOutputBuffer_auto_ptr& _Y) : _Owns(_Y._Owns), _Ptr(_Y.release()) {} xmlOutputBuffer_auto_ptr& operator=(const xmlOutputBuffer_auto_ptr& _Y) {if (this != &_Y) {if (_Ptr != _Y.get()) {if (_Owns && _Ptr) xmlOutputBufferClose(_Ptr); _Owns = _Y._Owns; } else if (_Y._Owns) _Owns = true; _Ptr = _Y.release(); } return (*this); } ~xmlOutputBuffer_auto_ptr() {if (_Owns && _Ptr) xmlOutputBufferClose(_Ptr); } xmlOutputBuffer& operator*() const {return (*get()); } xmlOutputBuffer *operator->() const {return (get()); } xmlOutputBuffer *get() const {return (_Ptr); } xmlOutputBuffer *release() const {((xmlOutputBuffer_auto_ptr *)this)->_Owns = false; return (_Ptr); } private: bool _Owns; xmlOutputBuffer *_Ptr; }; class xsltTransformContext_auto_ptr { public: explicit xsltTransformContext_auto_ptr(xsltTransformContext *_APtr = 0) : _Owns(_APtr != 0), _Ptr(_APtr) {} xsltTransformContext_auto_ptr(const xsltTransformContext_auto_ptr& _Y) : _Owns(_Y._Owns), _Ptr(_Y.release()) {} xsltTransformContext_auto_ptr& operator=(const xsltTransformContext_auto_ptr& _Y) {if (this != &_Y) {if (_Ptr != _Y.get()) {if (_Owns && _Ptr) xsltFreeTransformContext(_Ptr); _Owns = _Y._Owns; } else if (_Y._Owns) _Owns = true; _Ptr = _Y.release(); } return (*this); } ~xsltTransformContext_auto_ptr() {if (_Owns && _Ptr) xsltFreeTransformContext(_Ptr); } xsltTransformContext& operator*() const {return (*get()); } xsltTransformContext *operator->() const {return (get()); } xsltTransformContext *get() const {return (_Ptr); } xsltTransformContext *release() const {((xsltTransformContext_auto_ptr *)this)->_Owns = false; return (_Ptr); } private: bool _Owns; xsltTransformContext *_Ptr; }; class xsltStylesheet_auto_ptr { public: explicit xsltStylesheet_auto_ptr(xsltStylesheet *_APtr = 0) : _Owns(_APtr != 0), _Ptr(_APtr) {} xsltStylesheet_auto_ptr(const xsltStylesheet_auto_ptr& _Y) : _Owns(_Y._Owns), _Ptr(_Y.release()) {} xsltStylesheet_auto_ptr& operator=(const xsltStylesheet_auto_ptr& _Y) {if (this != &_Y) {if (_Ptr != _Y.get()) {if (_Owns && _Ptr) xsltFreeStylesheet(_Ptr); _Owns = _Y._Owns; } else if (_Y._Owns) _Owns = true; _Ptr = _Y.release(); } return (*this); } ~xsltStylesheet_auto_ptr() {if (_Owns && _Ptr) xsltFreeStylesheet(_Ptr); } xsltStylesheet& operator*() const {return (*get()); } xsltStylesheet *operator->() const {return (get()); } xsltStylesheet *get() const {return (_Ptr); } xsltStylesheet *release() const {((xsltStylesheet_auto_ptr *)this)->_Owns = false; return (_Ptr); } private: bool _Owns; xsltStylesheet *_Ptr; }; // methods static void writeNode(Request& r, StringPtr method_name, GdomeNode *node, GdomeException exc) { if(!node || exc) throw Exception( method_name, exc); Pool& pool=r.pool(); // write out result r.write_no_lang(ValuePtr(new VXnode(&pool, &r.charsets, node))); } // Element createElement(in DOMString tagName) raises(DOMException); static void _createElement(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr tagName=params->as_string(0, "tagName must be string"); GdomeException exc; GdomeNode *node= (GdomeNode *)gdome_doc_createElement(vdoc.get_document(method_name), r.transcode(tagName).get(), &exc); writeNode(r, method_name, node, exc); } // DocumentFragment createDocumentFragment() static void _createDocumentFragment(Request& r, StringPtr method_name, MethodParams* ) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); GdomeException exc; GdomeNode *node= (GdomeNode *)gdome_doc_createDocumentFragment( vdoc.get_document(method_name), &exc); writeNode(r, method_name, node, exc); } // Text createTextNode(in DOMString data); static void _createTextNode(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr data=params->as_string(0, "data must be string"); GdomeException exc; GdomeNode *node=(GdomeNode *)gdome_doc_createTextNode( vdoc.get_document(method_name), r.transcode(data).get(), &exc); writeNode(r, method_name, node, exc); } // Comment createComment(in DOMString data) static void _createComment(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr data=params->as_string(0, "data must be string"); GdomeException exc; GdomeNode *node=(GdomeNode *)gdome_doc_createComment( vdoc.get_document(method_name), r.transcode(data).get(), &exc); writeNode(r, method_name, node, exc); } // CDATASection createCDATASection(in DOMString data) raises(DOMException); static void _createCDATASection(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr data=params->as_string(0, "data must be string"); GdomeException exc; GdomeNode *node=(GdomeNode *)gdome_doc_createCDATASection( vdoc.get_document(method_name), r.transcode(data).get(), &exc); writeNode(r, method_name, node, exc); } // ProcessingInstruction createProcessingInstruction(in DOMString target,in DOMString data) raises(DOMException); static void _createProcessingInstruction(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr target=params->as_string(0, "data must be string"); StringPtr data=params->as_string(1, "data must be string"); GdomeException exc; GdomeNode *node=(GdomeNode *)gdome_doc_createProcessingInstruction( vdoc.get_document(method_name), r.transcode(target).get(), r.transcode(data).get(), &exc); writeNode(r, method_name, node, exc); } // Attr createAttribute(in DOMString name) raises(DOMException); static void _createAttribute(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr name=params->as_string(0, "name must be string"); GdomeException exc; GdomeNode *node=(GdomeNode *)gdome_doc_createAttribute( vdoc.get_document(method_name), r.transcode(name).get(), &exc); writeNode(r, method_name, node, exc); } // EntityReference createEntityReference(in DOMString name) raises(DOMException); static void _createEntityReference(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr name=params->as_string(0, "name must be string"); GdomeException exc; GdomeNode *node=(GdomeNode *)gdome_doc_createEntityReference( vdoc.get_document(method_name), r.transcode(name).get(), &exc); writeNode(r, method_name, node, exc); } // NodeList getElementsByTagName(in DOMString name); static void _getElementsByTagName(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr name=params->as_string(0, "name must be string"); VHashPtr result(new VHash); GdomeException exc; if(GdomeNodeList *nodes= gdome_doc_getElementsByTagName( vdoc.get_document(method_name), r.transcode(name).get(), &exc)) { gulong length=gdome_nl_length(nodes, &exc); for(gulong i=0; ihash(Exception::undefined_source).put( skey, ValuePtr(new VXnode(&pool, &r.charsets, gdome_nl_item(nodes, i, &exc)))); } } else if(exc) throw Exception( method_name, exc); // write out result r.write_no_lang(result); } static void _getElementsByTagNameNS(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); // namespaceURI;localName StringPtr namespaceURI=params->as_string(0, "namespaceURI must be string"); StringPtr localName=params->as_string(1, "localName must be string"); GdomeException exc; VHashPtr result(new VHash); if(GdomeNodeList *nodes= gdome_doc_getElementsByTagNameNS( vdoc.get_document(method_name), r.transcode(namespaceURI).get(), r.transcode(localName).get(), &exc)) { gulong length=gdome_nl_length(nodes, &exc); for(gulong i=0; ihash(Exception::undefined_source).put( skey, ValuePtr(new VXnode(&pool, &r.charsets, gdome_nl_item(nodes, i, &exc)))); } } // write out result r.write_no_lang(result); } static void _getElementById(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); // elementId StringPtr elementId=params->as_string(0, "elementID must be string"); GdomeException exc; if(GdomeNode *node=(GdomeNode *)gdome_doc_getElementById( vdoc.get_document(method_name), r.transcode(elementId).get(), &exc)) { // write out result r.write_no_lang(ValuePtr(new VXnode(&pool, &r.charsets, node))); } else if(exc || xmlHaveGenericErrors()) throw Exception( method_name, exc); } static void _importNode(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); GdomeNode *importedNode= as_node(method_name, params, 0, "importedNode must be node"); bool deep= params->as_bool(1, "deep must be bool", r); GdomeException exc; GdomeNode *outputNode=gdome_doc_importNode(vdoc.get_document(method_name), importedNode, deep, &exc); if(exc) throw Exception( method_name, exc); // write out result r.write_no_lang(ValuePtr(new VXnode(&pool, &r.charsets, outputNode))); } /* GdomeElement *gdome_doc_createElementNS (GdomeDocument *self, GdomeDOMString *namespaceURI, GdomeDOMString *qualifiedName, GdomeException *exc); GdomeAttr *gdome_doc_createAttributeNS (GdomeDocument *self, GdomeDOMString *namespaceURI, GdomeDOMString *qualifiedName, GdomeException *exc); */ static void _create(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); Charset& source_charset=r.charsets.source(); VXdoc& vdoc=GET_SELF(r, VXdoc); ValuePtr param=(*params)[params->count()-1]; GdomeDocument *document; if(param->get_junction()) { // {...} Temp_lang temp_lang(r, String::UL_XML); StringPtr xml=r.process_to_string(param); CharPtr cstr=xml->cstr(String::UL_UNSPECIFIED); document=(GdomeDocument *) gdome_xml_n_mkref((xmlNode *)xmlParseMemory( cstr, strlen(cstr) )); if(!document || xmlHaveGenericErrors()) { GdomeException exc=0; throw Exception( method_name, exc); } } else { // [name] StringPtr qualifiedName=param->as_string(&pool); GdomeException exc; /* GdomeDocumentType *documentType=gdome_di_createDocumentType ( docimpl, r.transcode(qualifiedName), 0/*publicId* /, 0/*systemId* /, &exc); if(!documentType || exc || xmlHaveGenericErrors()) throw Exception( method_name, exc); */ document=gdome_di_createDocument (domimpl, 0/*namespaceURI*/, r.transcode(qualifiedName).get(), 0/*doctype*/, &exc); if(!document || exc || xmlHaveGenericErrors()) throw Exception( method_name, exc); xmlDoc *doc=gdome_xml_doc_get_xmlDoc(document); CharPtr source_charset_name=source_charset.name()->cstr(); doc->encoding=source_charset.transcode_buf2xchar(source_charset_name, strlen(source_charset_name)); /// +xalan createXMLDecl ? } // URI const char* URI_cstr; CharPtr URI_cstr_ptr; if(params->count()>1) { // absolute(param) StringPtr URI=params->as_string(0, "URI must be string"); URI_cstr=URI_cstr_ptr=r.absolute(URI)->cstr(); } else // default = disk path to requested document URI_cstr=r.request_info.path_translated; xmlDoc *doc=gdome_xml_doc_get_xmlDoc(document); if(URI_cstr) doc->URL=source_charset.transcode_buf2xchar(URI_cstr, strlen(URI_cstr)); // replace any previous parsed source vdoc.set_document(&pool, document); } static void _load(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); Charset& source_charset=r.charsets.source(); VXdoc& vdoc=GET_SELF(r, VXdoc); // filespec StringPtr file_name=params->as_string(0, "uri must be string"); StringPtr uri=r.absolute(file_name); void *data; size_t size; File_read_result file=file_read(pool, source_charset, uri, false/*not text*/, params->count()>1?params->as_no_junction(1, "additional params must be hash") ->get_hash(method_name) :0); GdomeDocument *document=(GdomeDocument *) gdome_xml_n_mkref((xmlNode *)xmlParseMemory(file.data, file.size)); if(!document || xmlHaveGenericErrors()) { GdomeException exc=0; throw Exception(uri, exc); } CharPtr URI_cstr=uri->cstr(); xmlDoc *doc=gdome_xml_doc_get_xmlDoc(document); if(URI_cstr) doc->URL=source_charset.transcode_buf2xchar(URI_cstr, strlen(URI_cstr)); // replace any previous parsed source vdoc.set_document(&pool, document); } static void param_option_over_output_option(Pool& pool, HashStringValue& param_options, const char* option_name, StringPtr& output_option) { if(ValuePtr value=param_options.get(StringPtr(new String(option_name)))) output_option=value->as_string(&pool); } static void param_option_over_output_option(Pool& pool, HashStringValue& param_options, const char* option_name, bool& output_option) { if(ValuePtr value=param_options.get(StringPtr(new String(option_name)))) { StringPtr s=value->as_string(&pool); if(*s=="yes") output_option=true; else if(*s=="no") output_option=false; else throw Exception("parser.runtime", s, "%s must be either 'yes' or 'no'", option_name); } } /// @test valid_options check static void prepare_output_options(Request& r, StringPtr method_name, MethodParams* params, int index, VXdoc::Output_options& oo) { Pool& pool=r.pool(); /* */ // configuring with options from parameter... if(params->count()>index) { ValuePtr voptions=params->as_no_junction(index, "options must be string"); if(voptions->is_defined()) { if(HashStringValue *options=voptions->get_hash(method_name)) { // $.method[xml|html|text] if(ValuePtr vmethod=options->get(StringPtr(new String(XDOC_OUTPUT_METHOD_OPTION_NAME)))) oo.method=vmethod->as_string(&pool); // $.version[1.0] param_option_over_output_option(pool, *options, "version", oo.version); // $.encoding[windows-1251|...] param_option_over_output_option(pool, *options, "encoding", oo.encoding); // $.omit-xml-declaration[yes|no] param_option_over_output_option(pool, *options, "omit-xml-declaration", oo.omitXmlDeclaration); // $.standalone[yes|no] param_option_over_output_option(pool, *options, "standalone", oo.standalone); // $.doctype-public[?] param_option_over_output_option(pool, *options, "doctype-public", oo.doctypePublic); // $.doctype-system[?] param_option_over_output_option(pool, *options, "doctype-system", oo.doctypeSystem); // $.indent[yes|no] param_option_over_output_option(pool, *options, "indent", oo.indent); // $.media-type[text/{html|xml|plain}] param_option_over_output_option(pool, *options, "media-type", oo.mediaType); } } } // default encoding from pool if(!oo.encoding) oo.encoding=r.charsets.source().name(); // default method=xml if(!oo.method) oo.method=StringPtr(new String(XDOC_OUTPUT_METHOD_OPTION_VALUE_XML)); // default mediaType = depending on method if(!oo.mediaType) { if(*oo.method==XDOC_OUTPUT_METHOD_OPTION_VALUE_XML) oo.mediaType=StringPtr(new String("text/xml")); else if(*oo.method==XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML) oo.mediaType=StringPtr(new String("text/html")); else // XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT & all others oo.mediaType=StringPtr(new String("text/plain")); } } struct Xdoc2buf_result { char* ptr; size_t size; }; static Xdoc2buf_result xdoc2buf(Request& r, VXdoc& vdoc, StringPtr method_name, MethodParams* params, int index, VXdoc::Output_options& oo, StringPtr file_spec) { Xdoc2buf_result result; Pool& pool=r.pool(); prepare_output_options(r, method_name, params, index, oo); CharPtr encoding_cstr=oo.encoding->cstr(); xmlCharEncodingHandler *encoder=xmlFindCharEncodingHandler(encoding_cstr); if(!encoder) throw Exception("parser.runtime", method_name, "encoding '%s' not supported", encoding_cstr.get()); // UTF-8 encoder contains empty input/output converters, // which is wrong for xmlOutputBufferCreateIO // while zero encoder goes perfectly if(encoder && strcmp(encoder->name, "UTF-8")==0) encoder=0; xmlOutputBuffer_auto_ptr outputBuffer(xmlAllocOutputBuffer(encoder)); xsltStylesheet_auto_ptr stylesheet(xsltNewStylesheet()); if(!stylesheet.get()) throw Exception(0, method_name, "xsltNewStylesheet failed"); #define OOS2STYLE(name) \ stylesheet->name=oo.name?BAD_CAST g_strdup(r.transcode(oo.name)->str):0 #define OOE2STYLE(name) \ stylesheet->name=oo.name OOS2STYLE(method); OOS2STYLE(encoding); OOS2STYLE(mediaType); OOS2STYLE(doctypeSystem); OOS2STYLE(doctypePublic); OOE2STYLE(indent); OOS2STYLE(version); OOE2STYLE(standalone); OOE2STYLE(omitXmlDeclaration); xmlDoc *document=gdome_xml_doc_get_xmlDoc(vdoc.get_document(method_name)); if(xsltSaveResultTo(outputBuffer.get(), document, stylesheet.get())<0) { GdomeException exc=0; throw Exception( method_name, exc); } // write out result char *gnome_buf; size_t gnome_size; if(outputBuffer->conv) { gnome_size=outputBuffer->conv->use; gnome_buf=(char *)outputBuffer->conv->content; } else { gnome_size=outputBuffer->buffer->use; gnome_buf=(char *)outputBuffer->buffer->content; } if(file_spec) file_write(file_spec, gnome_buf, gnome_size, true/*as_text*/); else if(result.size=gnome_size) { result.ptr=pool.copy(gnome_buf, gnome_size); } else result.ptr=0; return result; } static void _file(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); VXdoc::Output_options oo(vdoc.output_options); Xdoc2buf_result buf=xdoc2buf(r, vdoc, method_name, params, 0, oo, StringPtr(0)/*not to file, to memory*/); // write out result r.write_no_lang(String(buf.ptr, buf.size)); // write out result VFilePtr vfile(new VFile); ValuePtr vcontent_type; VHashPtr vhcontent_type(new VHash); vhcontent_type->hash(method_name).put( value_name, ValuePtr(new VString(oo.mediaType))); vhcontent_type->hash(method_name).put( StringPtr(new String("charset")), ValuePtr(new VString(oo.encoding))); vcontent_type=vhcontent_type; vfile->set(pool, false/*tainted*/, buf.ptr?buf.ptr:""/*to distinguish from stat-ed file*/, buf.size, 0/*file_name*/, vcontent_type); r.write_no_lang(vfile); } static void _save(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); StringPtr file_spec=r.absolute(params->as_string(0, "file name must be string")); VXdoc::Output_options oo(vdoc.output_options); xdoc2buf(r, vdoc, method_name, params, 1, oo, file_spec); } static void _string(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); VXdoc::Output_options oo(vdoc.output_options); Xdoc2buf_result buf=xdoc2buf(r, vdoc, method_name, params, 0, oo, StringPtr(0)/*not to file, to memory*/); // write out result r.write_no_lang(String(buf.ptr, buf.size)); } #ifndef DOXYGEN struct Add_xslt_param_info { Request* r; const char** current_transform_param; }; #endif static void add_xslt_param( HashStringValue::key_type attribute, HashStringValue::value_type meaning, Add_xslt_param_info* info) { *info->current_transform_param++=info->r->transcode(attribute)->str; *info->current_transform_param++=info->r->transcode(meaning->as_string(&info->r->pool()))->str; } static VXdocPtr _transform(Request& r, StringPtr doc_source, StringPtr stylesheet_source, VXdoc& vdoc, xsltStylesheetPtr stylesheet, const char** transform_params) { Pool& pool=r.pool(); xmlDoc *document=gdome_xml_doc_get_xmlDoc(vdoc.get_document(doc_source)); xsltTransformContext_auto_ptr transformContext( xsltNewTransformContext(stylesheet, document)); // make params literal if (transformContext->globalVars == NULL) // strangly not initialized by xsltNewTransformContext transformContext->globalVars = xmlHashCreate(20); xsltQuoteUserParams(transformContext.get(), transform_params); // do transform xmlDoc *transformed=xsltApplyStylesheetUser( stylesheet, document, 0/*already quoted-inserted transform_params*/, 0/*const char* output*/, 0/*FILE *profile*/, transformContext.get()); if(!transformed || xmlHaveGenericErrors()) { GdomeException exc=0; throw Exception( stylesheet_source, exc); } //gdome_xml_doc_mkref dislikes XML_HTML_DOCUMENT_NODE type, fixing transformed->type=XML_DOCUMENT_NODE; // constructing result GdomeDocument *gdomeDocument=gdome_xml_doc_mkref(transformed); if(!gdomeDocument) throw Exception(0, doc_source, "gdome_xml_doc_mkref failed"); VXdocPtr result(new VXdoc(&pool, &r.charsets, gdomeDocument)); /* grabbing options */ VXdoc::Output_options& oo=result->output_options; Charset& source_charset=r.charsets.source(); oo.method=stylesheet->method?source_charset.transcode(stylesheet->method, stylesheet_source):StringPtr(0); oo.encoding=stylesheet->encoding?source_charset.transcode(stylesheet->encoding, stylesheet_source):StringPtr(0); oo.mediaType=stylesheet->mediaType?source_charset.transcode(stylesheet->mediaType, stylesheet_source):StringPtr(0); oo.doctypeSystem=stylesheet->doctypeSystem?source_charset.transcode(stylesheet->doctypeSystem, stylesheet_source):StringPtr(0); oo.doctypePublic=stylesheet->doctypePublic?source_charset.transcode(stylesheet->doctypePublic, stylesheet_source):StringPtr(0); oo.indent=stylesheet->indent!=0; oo.version=stylesheet->version?source_charset.transcode(stylesheet->version, stylesheet_source):StringPtr(0); oo.standalone=stylesheet->standalone!=0; oo.omitXmlDeclaration=stylesheet->omitXmlDeclaration!=0; // return return result; } static void _transform(Request& r, StringPtr method_name, MethodParams* params) { Pool& pool=r.pool(); VXdoc& vdoc=GET_SELF(r, VXdoc); // params smart_ptr transform_params; if(params->count()>1) { ValuePtr vparams=params->as_no_junction(1, "transform parameters must be hash"); if(!vparams->is_string()) if(HashStringValue* params=vparams->get_hash(method_name)) { transform_params=smart_ptr(new const char*[params->count()*2+1]); Add_xslt_param_info info={ &r, transform_params }; params->for_each(add_xslt_param, &info); transform_params[params->count()*2]=0; } else throw Exception("parser.runtime", method_name, "transform parameters parameter must be hash"); } VXdocPtr result; ValuePtr vmaybe_xdoc=(*params)[0]; if(Value *vxdoc=vmaybe_xdoc->as(VXDOC_TYPE, false)) { // stylesheet (xdoc) xmlDoc *document=gdome_xml_doc_get_xmlDoc( static_cast(vxdoc)->get_document(method_name)); // compile xdoc stylesheet xsltStylesheet_auto_ptr stylesheet_ptr(xsltParseStylesheetDoc(document)); // strange thing - xsltParseStylesheetDoc records document and destroys it in stylesheet destructor // we don't need that stylesheet_ptr->doc=0; if(xmlHaveGenericErrors()) { GdomeException exc=0; throw Exception(method_name, exc); } if(!stylesheet_ptr.get()) throw Exception("xml", method_name, "stylesheet failed to compile"); // transform! result=_transform(r, method_name, method_name, vdoc, stylesheet_ptr.get(), transform_params); } else { // stylesheet (file name) // extablish stylesheet connection StringPtr stylesheet_filespec= r.absolute(params->as_string(0, "stylesheet must be file name (string) or DOM document (xdoc)")); Stylesheet_connectionPtr connection=stylesheet_manager.get_connection(stylesheet_filespec); // load and compile file to stylesheet [or get cached if any] // transform! result=_transform(r, method_name, stylesheet_filespec, vdoc, connection->stylesheet(false/*nocache*/), transform_params); } // write out result r.write_no_lang(result); } // constructor /// @test how to create empty type html? MXdoc::MXdoc(): MXnode(XDOC_CLASS_NAME, xnode_class.get()) { /// DOM1 // Element createElement(in DOMString tagName) raises(DOMException); add_native_method("createElement", Method::CT_DYNAMIC, _createElement, 1, 1); // DocumentFragment createDocumentFragment(); add_native_method("createDocumentFragment", Method::CT_DYNAMIC, _createDocumentFragment, 0, 0); // Text createTextNode(in DOMString data); add_native_method("createTextNode", Method::CT_DYNAMIC, _createTextNode, 1, 1); // Comment createComment(in DOMString data); add_native_method("createComment", Method::CT_DYNAMIC, _createComment, 1, 1); // CDATASection createCDATASection(in DOMString data) raises(DOMException); add_native_method("createCDATASection", Method::CT_DYNAMIC, _createCDATASection, 1, 1); // ProcessingInstruction createProcessingInstruction(in DOMString target, in DOMString data) raises(DOMException); add_native_method("createProcessingInstruction", Method::CT_DYNAMIC, _createProcessingInstruction, 2, 2); // Attr createAttribute(in DOMString name) raises(DOMException); add_native_method("createAttribute", Method::CT_DYNAMIC, _createAttribute, 1, 1); // EntityReference createEntityReference(in DOMString name) raises(DOMException); add_native_method("createEntityReference", Method::CT_DYNAMIC, _createEntityReference, 1, 1); // NodeList getElementsByTagName(in DOMString name); add_native_method("getElementsByTagName", Method::CT_DYNAMIC, _getElementsByTagName, 1, 1); /// DOM2 // ^xdoc.getElementById[elementId] add_native_method("getElementById", Method::CT_DYNAMIC, _getElementById, 1, 1); // Node (in Node importedNode, in boolean deep) raises(DOMException) add_native_method("importNode", Method::CT_DYNAMIC, _importNode, 2, 2); // NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName); add_native_method("getElementsByTagNameNS", Method::CT_DYNAMIC, _getElementsByTagNameNS, 2, 2); /// parser // ^xdoc::create{qualifiedName} // ^xdoc::create[xml] // ^xdoc::create[URI][xml] add_native_method("create", Method::CT_DYNAMIC, _create, 1, 2); // for backward compatibility with <=v 1.82 2002/01/31 11:51:46 paf add_native_method("set", Method::CT_DYNAMIC, _create, 1, 1); // ^xdoc::load[some.xml] add_native_method("load", Method::CT_DYNAMIC, _load, 1, 2); // ^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.transform[stylesheet file_name/xdoc] // ^xdoc.transform[stylesheet file_name/xdoc;params hash] add_native_method("transform", Method::CT_DYNAMIC, _transform, 1, 2); } void MXdoc::configure_admin(Request& r) { } # else #endif