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

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

E-mail: