Annotation of parser3/src/classes/dom.C, revision 1.15

1.2       parser      1: /** @file
                      2:        Parser: @b dom parser class.
                      3: 
                      4:        Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
                      5: 
                      6:        Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
                      7: */
1.15    ! parser      8: static const char *RCSId="$Id: dom.C,v 1.14 2001/09/11 08:39:04 parser Exp $"; 
1.2       parser      9: 
                     10: #if _MSC_VER
                     11: #      pragma warning(disable:4291)   // disable warning 
                     12: //     "no matching operator delete found; memory will not be freed if initialization throws an exception
                     13: #endif
                     14: 
                     15: #include "classes.h"
                     16: #include "pa_request.h"
                     17: #include "pa_vdom.h"
1.9       parser     18: #include "pa_vfile.h"
1.2       parser     19: 
                     20: #include <Include/PlatformDefinitions.hpp>
                     21: #include <util/PlatformUtils.hpp>
1.5       parser     22: #include <util/XMLString.hpp>
1.2       parser     23: #include <XalanTransformer/XalanTransformer.hpp>
1.4       parser     24: #include <XalanTransformer/XalanParsedSource.hpp>
1.11      parser     25: //#include <XalanTransformer/XercesDOMParsedSource.hpp>
1.4       parser     26: #include <PlatformSupport/XalanFileOutputStream.hpp>
                     27: #include <PlatformSupport/XalanOutputStreamPrintWriter.hpp>
1.6       parser     28: #include <PlatformSupport/DOMStringPrintWriter.hpp>
1.4       parser     29: #include <XMLSupport/FormatterToXML.hpp>
1.13      parser     30: #include <XMLSupport/FormatterToHTML.hpp>
                     31: #include <XMLSupport/FormatterToText.hpp>
1.4       parser     32: #include <XMLSupport/FormatterTreeWalker.hpp>
1.11      parser     33: //#include <XercesParserLiaison/XercesDOMSupport.hpp>
1.6       parser     34: 
1.2       parser     35: // defines
                     36: 
1.4       parser     37: #define DOM_CLASS_NAME "dom"
1.2       parser     38: 
1.13      parser     39: #define DOM_OUTPUT_METHOD_OPTION_NAME "method"
                     40: #define DOM_OUTPUT_METHOD_OPTION_VALUE_XML "xml"
                     41: #define DOM_OUTPUT_METHOD_OPTION_VALUE_HTML "html"
                     42: #define DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT "text"
                     43: 
                     44: #define DOM_OUTPUT_ENCODING_OPTION_NAME "encoding"
                     45: 
                     46: #define DOM_OUTPUT_DEFAULT_INDENT 4
                     47: 
1.2       parser     48: // class
                     49: 
                     50: class MDom : public Methoded {
                     51: public: // VStateless_class
1.11      parser     52:        Value *create_new_value(Pool& pool) { return new(pool) VDom(pool); }
1.2       parser     53: 
                     54: public:
                     55:        MDom(Pool& pool);
                     56: 
                     57: public: // Methoded
                     58:        bool used_directly() { return true; }
                     59: };
                     60: 
                     61: // methods
                     62: 
                     63: static void _load(Request& r, const String& method_name, MethodParams *params) {
                     64:        Pool& pool=r.pool();
1.10      parser     65:        VDom& vDom=*static_cast<VDom *>(r.self);
1.2       parser     66: 
1.10      parser     67:        // filespec
1.2       parser     68:        const String& filename=params->as_string(0, "file name must not be code");
                     69:        const char *filespec=r.absolute(filename).cstr(String::UL_FILE_NAME);
                     70:        
                     71:        XalanParsedSource* parsedSource;
1.15    ! parser     72:        int error=vDom.get_transformer().parseSource(filespec, parsedSource);
1.2       parser     73: 
                     74:        if(error)
                     75:                PTHROW(0, 0,
                     76:                        &filename,
1.10      parser     77:                        vDom.get_transformer().getLastError());
1.2       parser     78: 
1.15    ! parser     79:        // replace any previous parsed source
1.11      parser     80:        vDom.set_parsed_source(*parsedSource);
1.2       parser     81: }
                     82: 
1.5       parser     83: const char *strX(const XalanDOMString& s) {
                     84:        return XMLString::transcode(s.c_str());
                     85: }
                     86: 
                     87: static void _throw(Pool& pool, const String *source, const XSLException& e) {
                     88:        if(e.getURI().empty())
                     89:                PTHROW(0, 0,
                     90:                        source,
                     91:                        "%s (%s)",
                     92:                                strX(e.getMessage()),  // message for exception
                     93:                                strX(e.getType()) // type of exception
                     94:                );
                     95:        else
                     96:                PTHROW(0, 0,
                     97:                        source,
                     98:                        "%s (%s) %s(%d:%d)'", 
                     99:                                strX(e.getMessage()),  // message for exception
                    100:                                strX(e.getType()), // type of exception
                    101:                                
                    102:                                strX(e.getURI()),  // URI for the associated document, if any
                    103:                                e.getLineNumber(),  // line number, or -1 if unknown
                    104:                                e.getColumnNumber() // column number, or -1 if unknown
                    105:                );
                    106: }
                    107: 
1.6       parser    108: class ParserStringOutputStream: public XalanOutputStream {
                    109: public:
                    110:        
1.7       parser    111:        explicit ParserStringOutputStream(String& astring) : fstring(astring) {}
                    112: 
                    113: protected: // XalanOutputStream
                    114: 
                    115:        virtual void writeData(const char *theBuffer, unsigned long theBufferLength) {
1.6       parser    116:                char *copy=(char *)fstring.malloc((size_t)theBufferLength);
                    117:                memcpy(copy, theBuffer, (size_t)theBufferLength);
                    118:                fstring.APPEND_CLEAN(copy, (size_t)theBufferLength, "dom", -1);
                    119:        }
                    120: 
1.7       parser    121:        virtual void doFlush() {}
1.6       parser    122: 
                    123: private:
                    124: 
                    125:        String& fstring;
                    126:        
                    127: };
                    128: 
                    129: 
1.13      parser    130: FormatterListener *create_optioned_listener(Pool& pool, 
                    131:                                                                   const String& method_name, MethodParams *params, int index,
                    132:                                                                   Writer& writer) {
                    133:        const String *method=0;
                    134:        XalanDOMString xalan_encoding;
                    135: 
                    136:        Value& voptions=params->as_no_junction(index, "options must not be code");
                    137:        if(voptions.is_defined()) {
                    138:                if(Hash *options=voptions.get_hash()) {
                    139:                        // $.method[xml|html|text]
1.15    ! parser    140:                        if(Value *vmethod=static_cast<Value *>(options->get(*new(pool) 
        !           141:                                String(pool, DOM_OUTPUT_METHOD_OPTION_NAME))))
        !           142:                                method=&vmethod->as_string();
1.13      parser    143: 
                    144:                        // $.encoding[windows-1251|...]
                    145:                        if(Value *vencoding=static_cast<Value *>(options->get(*new(pool) 
                    146:                                String(pool, DOM_OUTPUT_ENCODING_OPTION_NAME)))) {
                    147:                                const char *cstr=vencoding->as_string().cstr();
                    148:                                xalan_encoding.append(cstr, strlen(cstr));
                    149:                        }
                    150:                } else
                    151:                        PTHROW(0, 0,
                    152:                                &method_name,
                    153:                                "params must be hash");
                    154:        }
                    155: 
                    156:        if(!method/*default='xml'*/ || *method == DOM_OUTPUT_METHOD_OPTION_VALUE_XML)
                    157:                return new FormatterToXML(writer,
                    158:                        XalanDOMString(),  // version
                    159:                        true, // doIndent
                    160:                        DOM_OUTPUT_DEFAULT_INDENT, // indent 
                    161:                        xalan_encoding  // encoding
                    162:                );
                    163:        else if(*method == DOM_OUTPUT_METHOD_OPTION_VALUE_HTML)
                    164:                return new FormatterToHTML(writer,
                    165:                        xalan_encoding,  // encoding
                    166:                        XalanDOMString(),  // mediaType 
                    167:                        XalanDOMString(),  // doctypeSystem; String to be printed at the top of the document 
                    168:                        XalanDOMString(),  // doctypePublic  
                    169:                        true, // doIndent 
                    170:                        DOM_OUTPUT_DEFAULT_INDENT // indent 
                    171:                );
                    172:        else if(*method == DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT)
                    173:                return new FormatterToText(writer,
                    174:                        xalan_encoding  // encoding
                    175:                );
                    176:        else
                    177:                PTHROW(0, 0,
                    178:                        method,
1.14      parser    179:                        DOM_OUTPUT_METHOD_OPTION_NAME " option is invalid; valid methods are: "
                    180:                                "'" DOM_OUTPUT_METHOD_OPTION_VALUE_XML "', "
                    181:                                "'" DOM_OUTPUT_METHOD_OPTION_VALUE_HTML "', "
1.13      parser    182:                                "'" DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT "'");                   
                    183: 
                    184:        // never reached
                    185:        return 0; // calm, compiler
                    186: }
                    187: 
1.3       parser    188: static void _save(Request& r, const String& method_name, MethodParams *params) {
                    189:        Pool& pool=r.pool();
1.10      parser    190:        VDom& vDom=*static_cast<VDom *>(r.self);
1.3       parser    191: 
                    192:        // filespec
1.7       parser    193:        const String& filename=params->as_string(1, "file name must not be code");
1.3       parser    194:        const char *filespec=r.absolute(filename).cstr(String::UL_FILE_NAME);
                    195:        
1.11      parser    196:        // document
                    197:        XalanDocument& document=vDom.get_document(pool, &method_name);
1.3       parser    198: 
1.5       parser    199:        try {
1.6       parser    200:                XalanFileOutputStream stream(XalanDOMString(filespec, strlen(filespec)));
                    201:                XalanOutputStreamPrintWriter writer(stream);
1.13      parser    202:                FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0,
                    203:                        writer);
1.6       parser    204:                FormatterTreeWalker treeWalker(formatterListener);
1.11      parser    205:                treeWalker.traverse(&document); // Walk the document and produce the XML...
1.6       parser    206:        } catch(const XSLException& e) {
                    207:                _throw(pool, &method_name, e);
                    208:        }
                    209: }
                    210: 
                    211: static void _string(Request& r, const String& method_name, MethodParams *params) {
                    212:        Pool& pool=r.pool();
1.10      parser    213:        VDom& vDom=*static_cast<VDom *>(r.self);
1.6       parser    214: 
1.11      parser    215:        // document
                    216:        XalanDocument& document=vDom.get_document(pool, &method_name);
1.6       parser    217: 
                    218:        try {
1.9       parser    219:                String parserString=*new(pool) String(pool);
                    220:                ParserStringOutputStream stream(parserString);
1.6       parser    221:                XalanOutputStreamPrintWriter writer(stream);
1.13      parser    222:                FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0,
                    223:                        writer);
1.6       parser    224:                FormatterTreeWalker treeWalker(formatterListener);
1.11      parser    225:                treeWalker.traverse(&document); // Walk the document and produce the XML...
1.6       parser    226: 
                    227:                // write out result
1.9       parser    228:                r.write_no_lang(parserString);
1.5       parser    229:        } catch(const XSLException& e) {
                    230:                _throw(pool, &method_name, e);
                    231:        }
1.3       parser    232: }
                    233: 
1.9       parser    234: 
                    235: static void _file(Request& r, const String& method_name, MethodParams *params) {
                    236:        Pool& pool=r.pool();
1.10      parser    237:        VDom& vDom=*static_cast<VDom *>(r.self);
1.9       parser    238: 
1.11      parser    239:        // document
                    240:        XalanDocument& document=vDom.get_document(pool, &method_name);
1.9       parser    241: 
                    242:        try {
                    243:                String& parserString=*new(pool) String(pool);
                    244:                ParserStringOutputStream stream(parserString);
                    245:                XalanOutputStreamPrintWriter writer(stream);
1.13      parser    246:                FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0,
                    247:                        writer);
1.9       parser    248:                FormatterTreeWalker treeWalker(formatterListener);
1.11      parser    249:                treeWalker.traverse(&document); // Walk the document and produce the XML...
1.9       parser    250: 
                    251:                // write out result
                    252:                VFile& vfile=*new(pool) VFile(pool);
                    253:                const char *cstr=parserString.cstr();
                    254:                vfile.set(false/*tainted*/, cstr, strlen(cstr), 0/*filename*/, new(pool) String(pool, "text/xml"));
                    255:                r.write_no_lang(vfile);
                    256:        } catch(const XSLException& e) {
                    257:                _throw(pool, &method_name, e);
                    258:        }
                    259: }
                    260: 
                    261: 
1.12      parser    262: static void add_xslt_param(const Hash::Key& aattribute, Hash::Val *ameaning, 
                    263:                                                                 void *info) {
                    264:        XalanTransformer& transformer=*static_cast<XalanTransformer *>(info);
                    265:        const char *attribute_cstr=aattribute.cstr();
                    266:        const char *meaning_cstr=static_cast<Value *>(ameaning)->as_string().cstr();
                    267: 
                    268:        transformer.setStylesheetParam(
                    269:                XalanDOMString(attribute_cstr, strlen(attribute_cstr)),  
                    270:                XalanDOMString(meaning_cstr, strlen(meaning_cstr)));
                    271: }
1.10      parser    272: static void _xslt(Request& r, const String& method_name, MethodParams *params) {
                    273:        Pool& pool=r.pool();
                    274:        VDom& vDom=*static_cast<VDom *>(r.self);
                    275: 
1.12      parser    276:        // params
                    277:        if(params->size()>1) {
                    278:                Value& vparams=params->as_no_junction(1, "params must not be code");
                    279:                if(vparams.is_defined())
                    280:                        if(Hash *params=vparams.get_hash())
                    281:                                params->for_each(add_xslt_param, &vDom.get_transformer());
                    282:                        else
                    283:                                PTHROW(0, 0,
                    284:                                        &method_name,
                    285:                                        "params must be hash");
                    286:        }
                    287: 
1.10      parser    288:        // source
1.11      parser    289:        XalanParsedSource &parsed_source=vDom.get_parsed_source(pool, &method_name);
1.10      parser    290: 
                    291:        // stylesheet
                    292:        const String& stylesheet_filename=params->as_string(0, "file name must not be code");
                    293:        const char *stylesheet_filespec=r.absolute(stylesheet_filename).cstr(String::UL_FILE_NAME);
                    294: 
                    295:        // target
1.11      parser    296:        XalanDocument* target=vDom.get_parser_liaison().createDocument();
1.10      parser    297:        XSLTResultTarget domResultTarget(target);
                    298: 
                    299:        // transform
1.11      parser    300:        int error=vDom.get_transformer().transform(parsed_source, stylesheet_filespec, domResultTarget);
1.10      parser    301:        if(error)
                    302:                PTHROW(0, 0,
                    303:                        &stylesheet_filename,
                    304:                        vDom.get_transformer().getLastError());
                    305: 
                    306:        // write out result
1.11      parser    307:        VDom& result=*new(pool) VDom(pool);
                    308:        result.set_document(*target);
                    309:        r.write_no_lang(result);
1.10      parser    310: }
                    311: 
1.2       parser    312: // constructor
                    313: 
                    314: MDom::MDom(Pool& apool) : Methoded(apool) {
1.4       parser    315:        set_name(*NEW String(pool(), DOM_CLASS_NAME));
1.2       parser    316: 
1.3       parser    317:        // ^dom::load[some.xml]
1.2       parser    318:        add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
1.3       parser    319: 
1.13      parser    320:        // ^dom.save[options hash;some.xml]
1.8       parser    321:        add_native_method("save", Method::CT_DYNAMIC, _save, 2, 2);
1.2       parser    322: 
1.13      parser    323:        // ^dom.string[options hash] <doc/>
1.7       parser    324:        add_native_method("string", Method::CT_DYNAMIC, _string, 1, 1);
1.9       parser    325: 
1.13      parser    326:        // ^dom.file[options hash] file with "<doc/>"
1.9       parser    327:        add_native_method("file", Method::CT_DYNAMIC, _file, 1, 1);
1.10      parser    328: 
                    329:        // ^dom.xslt[stylesheet filename]
1.12      parser    330:        // ^dom.xslt[stylesheet filename;params hash]
                    331:        add_native_method("xslt", Method::CT_DYNAMIC, _xslt, 1, 2);
1.6       parser    332: 
1.2       parser    333: }
                    334: // global variable
                    335: 
                    336: Methoded *Dom_class;
                    337: 
                    338: // creator
                    339: 
                    340: Methoded *MDom_create(Pool& pool) {
                    341:        // Use the static initializers to initialize the Xalan-C++ and Xerces-C++ platforms. 
                    342:        // You must initialize Xerces-C++ once per process
                    343:        XMLPlatformUtils::Initialize();
                    344:        XalanTransformer::initialize();
                    345: 
                    346:        return Dom_class=new(pool) MDom(pool);
                    347: }

E-mail: