--- parser3/src/classes/Attic/dom.C 2001/09/10 11:17:41 1.9 +++ parser3/src/classes/Attic/dom.C 2001/09/11 09:14:04 1.16 @@ -5,7 +5,7 @@ Author: Alexander Petrosyan (http://design.ru/paf) */ -static const char *RCSId="$Id: dom.C,v 1.9 2001/09/10 11:17:41 parser Exp $"; +static const char *RCSId="$Id: dom.C,v 1.16 2001/09/11 09:14:04 parser Exp $"; #if _MSC_VER # pragma warning(disable:4291) // disable warning @@ -17,6 +17,7 @@ static const char *RCSId="$Id: dom.C,v 1 #include "pa_vdom.h" #include "pa_vfile.h" +#include #include #include #include @@ -26,18 +27,28 @@ static const char *RCSId="$Id: dom.C,v 1 #include #include #include +#include +#include #include - // defines #define DOM_CLASS_NAME "dom" +#define DOM_OUTPUT_METHOD_OPTION_NAME "method" +#define DOM_OUTPUT_METHOD_OPTION_VALUE_XML "xml" +#define DOM_OUTPUT_METHOD_OPTION_VALUE_HTML "html" +#define DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT "text" + +#define DOM_OUTPUT_ENCODING_OPTION_NAME "encoding" + +#define DOM_OUTPUT_DEFAULT_INDENT 4 + // class class MDom : public Methoded { public: // VStateless_class - Value *create_new_value(Pool& pool) { return new(pool) VDOM(pool, 0); } + Value *create_new_value(Pool& pool) { return new(pool) VDom(pool); } public: MDom(Pool& pool); @@ -48,29 +59,52 @@ public: // Methoded // methods -static void _load(Request& r, const String& method_name, MethodParams *params) { +/* +class istrstream : public istream { +public: + explicit istrstream(const char *s); + explicit istrstream(char *s); + istrstream(const char *s, streamsize n); + istrstream(char *s, streamsize n); + strstreambuf *rdbuf() const; + char *str(); + }; +*/ +static void _set(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); - VDOM& vDOM=*static_cast(r.self); + VDom& vDom=*static_cast(r.self); - // filename - const String& filename=params->as_string(0, "file name must not be code"); + std::istrstream stream(params->as_string(0, "parameter must not be code").cstr(String::UL_AS_IS)); + XalanParsedSource* parsedSource; + int error=vDom.get_transformer().parseSource(&stream, parsedSource); + + if(error) + PTHROW(0, 0, + &method_name, + vDom.get_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(); + VDom& vDom=*static_cast(r.self); // filespec + const String& filename=params->as_string(0, "file name must not be code"); const char *filespec=r.absolute(filename).cstr(String::UL_FILE_NAME); -// XSLTInputSource::XSLTInputSource ( std::istream * stream ) -// XalanNode *node=inputSource.getNode(); - XSLTInputSource inputSource(filespec); XalanParsedSource* parsedSource; - int error=vDOM.getXalanTransformer().parseSource(inputSource, parsedSource); + int error=vDom.get_transformer().parseSource(filespec, parsedSource); if(error) PTHROW(0, 0, &filename, - vDOM.getXalanTransformer().getLastError()); + vDom.get_transformer().getLastError()); - // replace any previous node value - vDOM.setParsedSource(parsedSource); + // replace any previous parsed source + vDom.set_parsed_source(*parsedSource); } const char *strX(const XalanDOMString& s) { @@ -120,35 +154,82 @@ private: }; +FormatterListener *create_optioned_listener(Pool& pool, + const String& method_name, MethodParams *params, int index, + Writer& writer) { + const String *method=0; + XalanDOMString xalan_encoding; + + 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, DOM_OUTPUT_METHOD_OPTION_NAME)))) + method=&vmethod->as_string(); + + // $.encoding[windows-1251|...] + if(Value *vencoding=static_cast(options->get(*new(pool) + String(pool, DOM_OUTPUT_ENCODING_OPTION_NAME)))) { + const char *cstr=vencoding->as_string().cstr(); + xalan_encoding.append(cstr, strlen(cstr)); + } + } else + PTHROW(0, 0, + &method_name, + "options must be hash"); + } + + if(!method/*default='xml'*/ || *method == DOM_OUTPUT_METHOD_OPTION_VALUE_XML) + return new FormatterToXML(writer, + XalanDOMString(), // version + true, // doIndent + DOM_OUTPUT_DEFAULT_INDENT, // indent + xalan_encoding // encoding + ); + else if(*method == DOM_OUTPUT_METHOD_OPTION_VALUE_HTML) + return new FormatterToHTML(writer, + xalan_encoding, // encoding + XalanDOMString(), // mediaType + XalanDOMString(), // doctypeSystem; String to be printed at the top of the document + XalanDOMString(), // doctypePublic + true, // doIndent + DOM_OUTPUT_DEFAULT_INDENT // indent + ); + else if(*method == DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT) + return new FormatterToText(writer, + xalan_encoding // encoding + ); + else + PTHROW(0, 0, + method, + DOM_OUTPUT_METHOD_OPTION_NAME " option is invalid; valid methods are: " + "'" DOM_OUTPUT_METHOD_OPTION_VALUE_XML "', " + "'" DOM_OUTPUT_METHOD_OPTION_VALUE_HTML "', " + "'" DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT "'"); + + // never reached + return 0; // calm, compiler +} + static void _save(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); - VDOM& vDOM=*static_cast(r.self); - - // encoding - const char *encoding=params->as_string(0, "encoding must not be code").cstr(); + VDom& vDom=*static_cast(r.self); // filespec const String& filename=params->as_string(1, "file name must not be code"); const char *filespec=r.absolute(filename).cstr(String::UL_FILE_NAME); - XalanParsedSource* parsedSource=vDOM.getParsedSource(); - if(!parsedSource) - PTHROW(0, 0, - &method_name, - "on empty document"); + // document + XalanDocument& document=vDom.get_document(pool, &method_name); try { - XalanDocument *document=parsedSource->getDocument(); XalanFileOutputStream stream(XalanDOMString(filespec, strlen(filespec))); XalanOutputStreamPrintWriter writer(stream); - FormatterToXML formatterListener(writer, - XalanDOMString(), // version - true , // doIndent - 4, // indent - XalanDOMString(encoding, strlen(encoding)) // encoding - ); + FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0, + writer); FormatterTreeWalker treeWalker(formatterListener); - treeWalker.traverse(document); // Walk the document and produce the XML... + treeWalker.traverse(&document); // Walk the document and produce the XML... } catch(const XSLException& e) { _throw(pool, &method_name, e); } @@ -156,34 +237,19 @@ static void _save(Request& r, const Stri static void _string(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); - VDOM& vDOM=*static_cast(r.self); - - // encoding - const char *encoding=params->as_string(0, "encoding must not be code").cstr(); + VDom& vDom=*static_cast(r.self); - XalanParsedSource* parsedSource=vDOM.getParsedSource(); - if(!parsedSource) - PTHROW(0, 0, - &method_name, - "on empty document"); + // document + XalanDocument& document=vDom.get_document(pool, &method_name); try { - XalanDocument *document=parsedSource->getDocument(); String parserString=*new(pool) String(pool); ParserStringOutputStream stream(parserString); XalanOutputStreamPrintWriter writer(stream); - FormatterToXML formatterListener(writer, - XalanDOMString(), // version - true , // doIndent - 4, // indent - XalanDOMString(encoding, strlen(encoding)), // encoding - XalanDOMString(), // mediaType - XalanDOMString(), // doctypeSystem - XalanDOMString(), // doctypePublic - false // xmlDecl - ); + FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0, + writer); FormatterTreeWalker treeWalker(formatterListener); - treeWalker.traverse(document); // Walk the document and produce the XML... + treeWalker.traverse(&document); // Walk the document and produce the XML... // write out result r.write_no_lang(parserString); @@ -195,30 +261,19 @@ static void _string(Request& r, const St static void _file(Request& r, const String& method_name, MethodParams *params) { Pool& pool=r.pool(); - VDOM& vDOM=*static_cast(r.self); + VDom& vDom=*static_cast(r.self); - // encoding - const char *encoding=params->as_string(0, "encoding must not be code").cstr(); - - XalanParsedSource* parsedSource=vDOM.getParsedSource(); - if(!parsedSource) - PTHROW(0, 0, - &method_name, - "on empty document"); + // document + XalanDocument& document=vDom.get_document(pool, &method_name); try { - XalanDocument *document=parsedSource->getDocument(); String& parserString=*new(pool) String(pool); ParserStringOutputStream stream(parserString); XalanOutputStreamPrintWriter writer(stream); - FormatterToXML formatterListener(writer, - XalanDOMString(), // version - true , // doIndent - 4, // indent - XalanDOMString(encoding, strlen(encoding)) // encoding - ); + FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0, + writer); FormatterTreeWalker treeWalker(formatterListener); - treeWalker.traverse(document); // Walk the document and produce the XML... + treeWalker.traverse(&document); // Walk the document and produce the XML... // write out result VFile& vfile=*new(pool) VFile(pool); @@ -231,23 +286,80 @@ static void _file(Request& r, const Stri } +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, strlen(attribute_cstr)), + XalanDOMString(meaning_cstr, strlen(meaning_cstr))); +} +static void _xslt(Request& r, const String& method_name, MethodParams *params) { + Pool& pool=r.pool(); + VDom& vDom=*static_cast(r.self); + + // params + if(params->size()>1) { + Value& vparams=params->as_no_junction(1, "params must not be code"); + if(vparams.is_defined()) + if(Hash *params=vparams.get_hash()) + params->for_each(add_xslt_param, &vDom.get_transformer()); + else + PTHROW(0, 0, + &method_name, + "params must be hash"); + } + + // source + XalanParsedSource &parsed_source=vDom.get_parsed_source(pool, &method_name); + + // stylesheet + const String& stylesheet_filename=params->as_string(0, "file name must not be code"); + const char *stylesheet_filespec=r.absolute(stylesheet_filename).cstr(String::UL_FILE_NAME); + + // target + XalanDocument* target=vDom.get_parser_liaison().createDocument(); + XSLTResultTarget domResultTarget(target); + + // transform + int error=vDom.get_transformer().transform(parsed_source, stylesheet_filespec, domResultTarget); + if(error) + PTHROW(0, 0, + &stylesheet_filename, + vDom.get_transformer().getLastError()); + + // write out result + VDom& result=*new(pool) VDom(pool); + result.set_document(*target); + r.write_no_lang(result); +} + // constructor MDom::MDom(Pool& apool) : Methoded(apool) { set_name(*NEW String(pool(), DOM_CLASS_NAME)); + // ^dom::set[xml] + add_native_method("set", Method::CT_DYNAMIC, _set, 1, 1); + // ^dom::load[some.xml] add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1); - // ^dom.save[encoding;some.xml] + // ^dom.save[options hash;some.xml] add_native_method("save", Method::CT_DYNAMIC, _save, 2, 2); - // ^dom.string[encoding] + // ^dom.string[options hash] add_native_method("string", Method::CT_DYNAMIC, _string, 1, 1); - // ^dom.file[encoding] file with "" + // ^dom.file[options hash] file with "" add_native_method("file", Method::CT_DYNAMIC, _file, 1, 1); + // ^dom.xslt[stylesheet filename] + // ^dom.xslt[stylesheet filename;params hash] + add_native_method("xslt", Method::CT_DYNAMIC, _xslt, 1, 2); + } // global variable