Annotation of parser3/src/classes/dom.C, revision 1.18
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.18 ! parser 8: static const char *RCSId="$Id: dom.C,v 1.17 2001/09/11 09:20:57 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(
! 151: const char *& content_type, FormatterListener *& listener,
! 152: Pool& pool,
! 153: const String& method_name, MethodParams *params, int index, Writer& writer) {
1.13 parser 154: const String *method=0;
155: XalanDOMString xalan_encoding;
156:
157: Value& voptions=params->as_no_junction(index, "options must not be code");
158: if(voptions.is_defined()) {
159: if(Hash *options=voptions.get_hash()) {
160: // $.method[xml|html|text]
1.15 parser 161: if(Value *vmethod=static_cast<Value *>(options->get(*new(pool)
162: String(pool, DOM_OUTPUT_METHOD_OPTION_NAME))))
163: method=&vmethod->as_string();
1.13 parser 164:
165: // $.encoding[windows-1251|...]
166: if(Value *vencoding=static_cast<Value *>(options->get(*new(pool)
167: String(pool, DOM_OUTPUT_ENCODING_OPTION_NAME)))) {
168: const char *cstr=vencoding->as_string().cstr();
169: xalan_encoding.append(cstr, strlen(cstr));
170: }
171: } else
172: PTHROW(0, 0,
173: &method_name,
1.16 parser 174: "options must be hash");
1.13 parser 175: }
176:
1.18 ! parser 177: if(!method/*default='xml'*/ || *method == DOM_OUTPUT_METHOD_OPTION_VALUE_XML) {
! 178: content_type="text/xml";
! 179: listener=new FormatterToXML(writer,
1.13 parser 180: XalanDOMString(), // version
181: true, // doIndent
182: DOM_OUTPUT_DEFAULT_INDENT, // indent
183: xalan_encoding // encoding
184: );
1.18 ! parser 185: } else if(*method == DOM_OUTPUT_METHOD_OPTION_VALUE_HTML) {
! 186: content_type="text/html";
! 187: listener=new FormatterToHTML(writer,
1.13 parser 188: xalan_encoding, // encoding
189: XalanDOMString(), // mediaType
190: XalanDOMString(), // doctypeSystem; String to be printed at the top of the document
191: XalanDOMString(), // doctypePublic
192: true, // doIndent
193: DOM_OUTPUT_DEFAULT_INDENT // indent
194: );
1.18 ! parser 195: } else if(*method == DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT) {
! 196: content_type="text/plain";
! 197: listener=new FormatterToText(writer,
1.13 parser 198: xalan_encoding // encoding
199: );
1.18 ! parser 200: } else
1.13 parser 201: PTHROW(0, 0,
202: method,
1.14 parser 203: DOM_OUTPUT_METHOD_OPTION_NAME " option is invalid; valid methods are: "
204: "'" DOM_OUTPUT_METHOD_OPTION_VALUE_XML "', "
205: "'" DOM_OUTPUT_METHOD_OPTION_VALUE_HTML "', "
1.13 parser 206: "'" DOM_OUTPUT_METHOD_OPTION_VALUE_TEXT "'");
207:
208: // never reached
209: }
210:
1.3 parser 211: static void _save(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.3 parser 214:
215: // filespec
1.7 parser 216: const String& filename=params->as_string(1, "file name must not be code");
1.3 parser 217: const char *filespec=r.absolute(filename).cstr(String::UL_FILE_NAME);
218:
1.11 parser 219: // document
220: XalanDocument& document=vDom.get_document(pool, &method_name);
1.3 parser 221:
1.5 parser 222: try {
1.6 parser 223: XalanFileOutputStream stream(XalanDOMString(filespec, strlen(filespec)));
224: XalanOutputStreamPrintWriter writer(stream);
1.18 ! parser 225: const char *content_type;
! 226: FormatterListener *formatterListener;
! 227: create_optioned_listener(content_type, formatterListener,
! 228: pool, method_name, params, 0, writer);
! 229: FormatterTreeWalker treeWalker(*formatterListener);
1.11 parser 230: treeWalker.traverse(&document); // Walk the document and produce the XML...
1.6 parser 231: } catch(const XSLException& e) {
232: _throw(pool, &method_name, e);
233: }
234: }
235:
236: static void _string(Request& r, const String& method_name, MethodParams *params) {
237: Pool& pool=r.pool();
1.10 parser 238: VDom& vDom=*static_cast<VDom *>(r.self);
1.6 parser 239:
1.11 parser 240: // document
241: XalanDocument& document=vDom.get_document(pool, &method_name);
1.6 parser 242:
243: try {
1.9 parser 244: String parserString=*new(pool) String(pool);
1.18 ! parser 245: ParserStringXalanOutputStream stream(parserString);
1.6 parser 246: XalanOutputStreamPrintWriter writer(stream);
1.18 ! parser 247: const char *content_type;
! 248: FormatterListener *formatterListener;
! 249: create_optioned_listener(content_type, formatterListener,
! 250: pool, method_name, params, 0, writer);
! 251: FormatterTreeWalker treeWalker(*formatterListener);
1.11 parser 252: treeWalker.traverse(&document); // Walk the document and produce the XML...
1.6 parser 253:
254: // write out result
1.9 parser 255: r.write_no_lang(parserString);
1.5 parser 256: } catch(const XSLException& e) {
257: _throw(pool, &method_name, e);
258: }
1.3 parser 259: }
260:
1.9 parser 261:
262: static void _file(Request& r, const String& method_name, MethodParams *params) {
263: Pool& pool=r.pool();
1.10 parser 264: VDom& vDom=*static_cast<VDom *>(r.self);
1.9 parser 265:
1.11 parser 266: // document
267: XalanDocument& document=vDom.get_document(pool, &method_name);
1.9 parser 268:
269: try {
270: String& parserString=*new(pool) String(pool);
1.18 ! parser 271: ParserStringXalanOutputStream stream(parserString);
1.9 parser 272: XalanOutputStreamPrintWriter writer(stream);
1.18 ! parser 273: const char *content_type;
! 274: FormatterListener *formatterListener;
! 275: create_optioned_listener(content_type, formatterListener,
! 276: pool, method_name, params, 0, writer);
! 277: FormatterTreeWalker treeWalker(*formatterListener);
1.11 parser 278: treeWalker.traverse(&document); // Walk the document and produce the XML...
1.9 parser 279:
280: // write out result
281: VFile& vfile=*new(pool) VFile(pool);
282: const char *cstr=parserString.cstr();
1.18 ! parser 283: vfile.set(false/*tainted*/, cstr, strlen(cstr), 0/*filename*/, new(pool) String(pool, content_type));
1.9 parser 284: r.write_no_lang(vfile);
285: } catch(const XSLException& e) {
286: _throw(pool, &method_name, e);
287: }
288: }
289:
290:
1.12 parser 291: static void add_xslt_param(const Hash::Key& aattribute, Hash::Val *ameaning,
292: void *info) {
293: XalanTransformer& transformer=*static_cast<XalanTransformer *>(info);
294: const char *attribute_cstr=aattribute.cstr();
295: const char *meaning_cstr=static_cast<Value *>(ameaning)->as_string().cstr();
296:
297: transformer.setStylesheetParam(
298: XalanDOMString(attribute_cstr, strlen(attribute_cstr)),
299: XalanDOMString(meaning_cstr, strlen(meaning_cstr)));
300: }
1.10 parser 301: static void _xslt(Request& r, const String& method_name, MethodParams *params) {
302: Pool& pool=r.pool();
303: VDom& vDom=*static_cast<VDom *>(r.self);
304:
1.12 parser 305: // params
306: if(params->size()>1) {
1.18 ! parser 307: Value& vparams=params->as_no_junction(1, "transform parameters parameter must not be code");
1.12 parser 308: if(vparams.is_defined())
309: if(Hash *params=vparams.get_hash())
310: params->for_each(add_xslt_param, &vDom.get_transformer());
311: else
312: PTHROW(0, 0,
313: &method_name,
1.18 ! parser 314: "transform parameters parameter must be hash");
1.12 parser 315: }
316:
1.10 parser 317: // source
1.11 parser 318: XalanParsedSource &parsed_source=vDom.get_parsed_source(pool, &method_name);
1.10 parser 319:
320: // stylesheet
321: const String& stylesheet_filename=params->as_string(0, "file name must not be code");
322: const char *stylesheet_filespec=r.absolute(stylesheet_filename).cstr(String::UL_FILE_NAME);
323:
324: // target
1.11 parser 325: XalanDocument* target=vDom.get_parser_liaison().createDocument();
1.10 parser 326: XSLTResultTarget domResultTarget(target);
327:
328: // transform
1.11 parser 329: int error=vDom.get_transformer().transform(parsed_source, stylesheet_filespec, domResultTarget);
1.10 parser 330: if(error)
331: PTHROW(0, 0,
332: &stylesheet_filename,
333: vDom.get_transformer().getLastError());
334:
335: // write out result
1.11 parser 336: VDom& result=*new(pool) VDom(pool);
337: result.set_document(*target);
338: r.write_no_lang(result);
1.10 parser 339: }
340:
1.2 parser 341: // constructor
342:
343: MDom::MDom(Pool& apool) : Methoded(apool) {
1.4 parser 344: set_name(*NEW String(pool(), DOM_CLASS_NAME));
1.16 parser 345:
346: // ^dom::set[<some>xml</some>]
347: add_native_method("set", Method::CT_DYNAMIC, _set, 1, 1);
1.2 parser 348:
1.3 parser 349: // ^dom::load[some.xml]
1.2 parser 350: add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
1.3 parser 351:
1.13 parser 352: // ^dom.save[options hash;some.xml]
1.8 parser 353: add_native_method("save", Method::CT_DYNAMIC, _save, 2, 2);
1.2 parser 354:
1.13 parser 355: // ^dom.string[options hash] <doc/>
1.7 parser 356: add_native_method("string", Method::CT_DYNAMIC, _string, 1, 1);
1.9 parser 357:
1.13 parser 358: // ^dom.file[options hash] file with "<doc/>"
1.9 parser 359: add_native_method("file", Method::CT_DYNAMIC, _file, 1, 1);
1.10 parser 360:
361: // ^dom.xslt[stylesheet filename]
1.12 parser 362: // ^dom.xslt[stylesheet filename;params hash]
363: add_native_method("xslt", Method::CT_DYNAMIC, _xslt, 1, 2);
1.6 parser 364:
1.2 parser 365: }
366: // global variable
367:
368: Methoded *Dom_class;
369:
370: // creator
371:
372: Methoded *MDom_create(Pool& pool) {
373: // Use the static initializers to initialize the Xalan-C++ and Xerces-C++ platforms.
374: // You must initialize Xerces-C++ once per process
375: XMLPlatformUtils::Initialize();
376: XalanTransformer::initialize();
377:
378: return Dom_class=new(pool) MDom(pool);
379: }
E-mail: