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