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

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.13    ! parser      8: static const char *RCSId="$Id: dom.C,v 1.12 2001/09/10 14:42:05 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:        XSLTInputSource inputSource(filespec);
                     72:        XalanParsedSource* parsedSource;
1.10      parser     73:        int error=vDom.get_transformer().parseSource(inputSource, parsedSource);
1.2       parser     74: 
                     75:        if(error)
                     76:                PTHROW(0, 0,
                     77:                        &filename,
1.10      parser     78:                        vDom.get_transformer().getLastError());
1.2       parser     79: 
                     80:        // replace any previous node value
1.11      parser     81:        vDom.set_parsed_source(*parsedSource);
1.2       parser     82: }
                     83: 
1.5       parser     84: const char *strX(const XalanDOMString& s) {
                     85:        return XMLString::transcode(s.c_str());
                     86: }
                     87: 
                     88: static void _throw(Pool& pool, const String *source, const XSLException& e) {
                     89:        if(e.getURI().empty())
                     90:                PTHROW(0, 0,
                     91:                        source,
                     92:                        "%s (%s)",
                     93:                                strX(e.getMessage()),  // message for exception
                     94:                                strX(e.getType()) // type of exception
                     95:                );
                     96:        else
                     97:                PTHROW(0, 0,
                     98:                        source,
                     99:                        "%s (%s) %s(%d:%d)'", 
                    100:                                strX(e.getMessage()),  // message for exception
                    101:                                strX(e.getType()), // type of exception
                    102:                                
                    103:                                strX(e.getURI()),  // URI for the associated document, if any
                    104:                                e.getLineNumber(),  // line number, or -1 if unknown
                    105:                                e.getColumnNumber() // column number, or -1 if unknown
                    106:                );
                    107: }
                    108: 
1.6       parser    109: class ParserStringOutputStream: public XalanOutputStream {
                    110: public:
                    111:        
1.7       parser    112:        explicit ParserStringOutputStream(String& astring) : fstring(astring) {}
                    113: 
                    114: protected: // XalanOutputStream
                    115: 
                    116:        virtual void writeData(const char *theBuffer, unsigned long theBufferLength) {
1.6       parser    117:                char *copy=(char *)fstring.malloc((size_t)theBufferLength);
                    118:                memcpy(copy, theBuffer, (size_t)theBufferLength);
                    119:                fstring.APPEND_CLEAN(copy, (size_t)theBufferLength, "dom", -1);
                    120:        }
                    121: 
1.7       parser    122:        virtual void doFlush() {}
1.6       parser    123: 
                    124: private:
                    125: 
                    126:        String& fstring;
                    127:        
                    128: };
                    129: 
                    130: 
1.13    ! parser    131: FormatterListener *create_optioned_listener(Pool& pool, 
        !           132:                                                                   const String& method_name, MethodParams *params, int index,
        !           133:                                                                   Writer& writer) {
        !           134:        const String *method=0;
        !           135:        XalanDOMString xalan_encoding;
        !           136: 
        !           137:        Value& voptions=params->as_no_junction(index, "options must not be code");
        !           138:        if(voptions.is_defined()) {
        !           139:                if(Hash *options=voptions.get_hash()) {
        !           140:                        // $.method[xml|html|text]
        !           141:                        method=options->get_string(*new(pool) String(pool, DOM_OUTPUT_METHOD_OPTION_NAME));
        !           142: 
        !           143:                        // $.encoding[windows-1251|...]
        !           144:                        if(Value *vencoding=static_cast<Value *>(options->get(*new(pool) 
        !           145:                                String(pool, DOM_OUTPUT_ENCODING_OPTION_NAME)))) {
        !           146:                                const char *cstr=vencoding->as_string().cstr();
        !           147:                                xalan_encoding.append(cstr, strlen(cstr));
        !           148:                        }
        !           149:                } else
        !           150:                        PTHROW(0, 0,
        !           151:                                &method_name,
        !           152:                                "params must be hash");
        !           153:        }
        !           154: 
        !           155:        if(!method/*default='xml'*/ || *method == DOM_OUTPUT_METHOD_OPTION_VALUE_XML)
        !           156:                return new FormatterToXML(writer,
        !           157:                        XalanDOMString(),  // version
        !           158:                        true, // doIndent
        !           159:                        DOM_OUTPUT_DEFAULT_INDENT, // indent 
        !           160:                        xalan_encoding  // encoding
        !           161:                );
        !           162:        else if(*method == DOM_OUTPUT_METHOD_OPTION_VALUE_HTML)
        !           163:                return new FormatterToHTML(writer,
        !           164:                        xalan_encoding,  // encoding
        !           165:                        XalanDOMString(),  // mediaType 
        !           166:                        XalanDOMString(),  // doctypeSystem; String to be printed at the top of the document 
        !           167:                        XalanDOMString(),  // doctypePublic  
        !           168:                        true, // doIndent 
        !           169:                        DOM_OUTPUT_DEFAULT_INDENT // indent 
        !           170:                );
        !           171:        else if(*method == DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT)
        !           172:                return new FormatterToText(writer,
        !           173:                        xalan_encoding  // encoding
        !           174:                );
        !           175:        else
        !           176:                PTHROW(0, 0,
        !           177:                        method,
        !           178:                        DOM_OUTPUT_METHOD_OPTION_NAME "option must be "
        !           179:                                "'" DOM_OUTPUT_METHOD_OPTION_VALUE_XML "' or "
        !           180:                                "'" DOM_OUTPUT_METHOD_OPTION_VALUE_HTML "' or "
        !           181:                                "'" DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT "'");                   
        !           182: 
        !           183:        // never reached
        !           184:        return 0; // calm, compiler
        !           185: }
        !           186: 
1.3       parser    187: static void _save(Request& r, const String& method_name, MethodParams *params) {
                    188:        Pool& pool=r.pool();
1.10      parser    189:        VDom& vDom=*static_cast<VDom *>(r.self);
1.3       parser    190: 
                    191:        // filespec
1.7       parser    192:        const String& filename=params->as_string(1, "file name must not be code");
1.3       parser    193:        const char *filespec=r.absolute(filename).cstr(String::UL_FILE_NAME);
                    194:        
1.11      parser    195:        // document
                    196:        XalanDocument& document=vDom.get_document(pool, &method_name);
1.3       parser    197: 
1.5       parser    198:        try {
1.6       parser    199:                XalanFileOutputStream stream(XalanDOMString(filespec, strlen(filespec)));
                    200:                XalanOutputStreamPrintWriter writer(stream);
1.13    ! parser    201:                FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0,
        !           202:                        writer);
1.6       parser    203:                FormatterTreeWalker treeWalker(formatterListener);
1.11      parser    204:                treeWalker.traverse(&document); // Walk the document and produce the XML...
1.6       parser    205:        } catch(const XSLException& e) {
                    206:                _throw(pool, &method_name, e);
                    207:        }
                    208: }
                    209: 
                    210: static void _string(Request& r, const String& method_name, MethodParams *params) {
                    211:        Pool& pool=r.pool();
1.10      parser    212:        VDom& vDom=*static_cast<VDom *>(r.self);
1.6       parser    213: 
1.11      parser    214:        // document
                    215:        XalanDocument& document=vDom.get_document(pool, &method_name);
1.6       parser    216: 
                    217:        try {
1.9       parser    218:                String parserString=*new(pool) String(pool);
                    219:                ParserStringOutputStream stream(parserString);
1.6       parser    220:                XalanOutputStreamPrintWriter writer(stream);
1.13    ! parser    221:                FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0,
        !           222:                        writer);
1.6       parser    223:                FormatterTreeWalker treeWalker(formatterListener);
1.11      parser    224:                treeWalker.traverse(&document); // Walk the document and produce the XML...
1.6       parser    225: 
                    226:                // write out result
1.9       parser    227:                r.write_no_lang(parserString);
1.5       parser    228:        } catch(const XSLException& e) {
                    229:                _throw(pool, &method_name, e);
                    230:        }
1.3       parser    231: }
                    232: 
1.9       parser    233: 
                    234: static void _file(Request& r, const String& method_name, MethodParams *params) {
                    235:        Pool& pool=r.pool();
1.10      parser    236:        VDom& vDom=*static_cast<VDom *>(r.self);
1.9       parser    237: 
1.11      parser    238:        // document
                    239:        XalanDocument& document=vDom.get_document(pool, &method_name);
1.9       parser    240: 
                    241:        try {
                    242:                String& parserString=*new(pool) String(pool);
                    243:                ParserStringOutputStream stream(parserString);
                    244:                XalanOutputStreamPrintWriter writer(stream);
1.13    ! parser    245:                FormatterListener& formatterListener=*create_optioned_listener(pool, method_name, params, 0,
        !           246:                        writer);
1.9       parser    247:                FormatterTreeWalker treeWalker(formatterListener);
1.11      parser    248:                treeWalker.traverse(&document); // Walk the document and produce the XML...
1.9       parser    249: 
                    250:                // write out result
                    251:                VFile& vfile=*new(pool) VFile(pool);
                    252:                const char *cstr=parserString.cstr();
                    253:                vfile.set(false/*tainted*/, cstr, strlen(cstr), 0/*filename*/, new(pool) String(pool, "text/xml"));
                    254:                r.write_no_lang(vfile);
                    255:        } catch(const XSLException& e) {
                    256:                _throw(pool, &method_name, e);
                    257:        }
                    258: }
                    259: 
                    260: 
1.12      parser    261: static void add_xslt_param(const Hash::Key& aattribute, Hash::Val *ameaning, 
                    262:                                                                 void *info) {
                    263:        XalanTransformer& transformer=*static_cast<XalanTransformer *>(info);
                    264:        const char *attribute_cstr=aattribute.cstr();
                    265:        const char *meaning_cstr=static_cast<Value *>(ameaning)->as_string().cstr();
                    266: 
                    267:        transformer.setStylesheetParam(
                    268:                XalanDOMString(attribute_cstr, strlen(attribute_cstr)),  
                    269:                XalanDOMString(meaning_cstr, strlen(meaning_cstr)));
                    270: }
1.10      parser    271: static void _xslt(Request& r, const String& method_name, MethodParams *params) {
                    272:        Pool& pool=r.pool();
                    273:        VDom& vDom=*static_cast<VDom *>(r.self);
                    274: 
1.12      parser    275:        // params
                    276:        if(params->size()>1) {
                    277:                Value& vparams=params->as_no_junction(1, "params must not be code");
                    278:                if(vparams.is_defined())
                    279:                        if(Hash *params=vparams.get_hash())
                    280:                                params->for_each(add_xslt_param, &vDom.get_transformer());
                    281:                        else
                    282:                                PTHROW(0, 0,
                    283:                                        &method_name,
                    284:                                        "params must be hash");
                    285:        }
                    286: 
1.10      parser    287:        // source
1.11      parser    288:        XalanParsedSource &parsed_source=vDom.get_parsed_source(pool, &method_name);
1.10      parser    289: 
                    290:        // stylesheet
                    291:        const String& stylesheet_filename=params->as_string(0, "file name must not be code");
                    292:        const char *stylesheet_filespec=r.absolute(stylesheet_filename).cstr(String::UL_FILE_NAME);
                    293: 
                    294:        // target
1.11      parser    295:        XalanDocument* target=vDom.get_parser_liaison().createDocument();
1.10      parser    296:        XSLTResultTarget domResultTarget(target);
                    297: 
                    298:        // transform
1.11      parser    299:        int error=vDom.get_transformer().transform(parsed_source, stylesheet_filespec, domResultTarget);
1.10      parser    300:        if(error)
                    301:                PTHROW(0, 0,
                    302:                        &stylesheet_filename,
                    303:                        vDom.get_transformer().getLastError());
                    304: 
                    305:        // write out result
1.11      parser    306:        VDom& result=*new(pool) VDom(pool);
                    307:        result.set_document(*target);
                    308:        r.write_no_lang(result);
1.10      parser    309: }
                    310: 
1.2       parser    311: // constructor
                    312: 
                    313: MDom::MDom(Pool& apool) : Methoded(apool) {
1.4       parser    314:        set_name(*NEW String(pool(), DOM_CLASS_NAME));
1.2       parser    315: 
1.3       parser    316:        // ^dom::load[some.xml]
1.2       parser    317:        add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
1.3       parser    318: 
1.13    ! parser    319:        // ^dom.save[options hash;some.xml]
1.8       parser    320:        add_native_method("save", Method::CT_DYNAMIC, _save, 2, 2);
1.2       parser    321: 
1.13    ! parser    322:        // ^dom.string[options hash] <doc/>
1.7       parser    323:        add_native_method("string", Method::CT_DYNAMIC, _string, 1, 1);
1.9       parser    324: 
1.13    ! parser    325:        // ^dom.file[options hash] file with "<doc/>"
1.9       parser    326:        add_native_method("file", Method::CT_DYNAMIC, _file, 1, 1);
1.10      parser    327: 
                    328:        // ^dom.xslt[stylesheet filename]
1.12      parser    329:        // ^dom.xslt[stylesheet filename;params hash]
                    330:        add_native_method("xslt", Method::CT_DYNAMIC, _xslt, 1, 2);
1.6       parser    331: 
1.2       parser    332: }
                    333: // global variable
                    334: 
                    335: Methoded *Dom_class;
                    336: 
                    337: // creator
                    338: 
                    339: Methoded *MDom_create(Pool& pool) {
                    340:        // Use the static initializers to initialize the Xalan-C++ and Xerces-C++ platforms. 
                    341:        // You must initialize Xerces-C++ once per process
                    342:        XMLPlatformUtils::Initialize();
                    343:        XalanTransformer::initialize();
                    344: 
                    345:        return Dom_class=new(pool) MDom(pool);
                    346: }

E-mail: