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: