Annotation of parser3/src/classes/xdoc.C, revision 1.3
1.1 parser 1: /** @file
1.2 parser 2: Parser: @b xdoc parser class.
1.1 parser 3:
4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
5: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
6:
1.3 ! parser 7: $Id: xdoc.C,v 1.2 2001/09/26 15:43:59 parser Exp $
1.1 parser 8: */
9: #include "classes.h"
10: #ifdef XML
11:
12: #include "pa_request.h"
13: #include "pa_vxdoc.h"
14: #include "pa_xslt_stylesheet_manager.h"
15: #include "pa_stylesheet_connection.h"
16: #include "pa_vfile.h"
17: #include "xnode.h"
18:
19: #include <strstream>
20: #include <Include/PlatformDefinitions.hpp>
21: #include <util/PlatformUtils.hpp>
22: #include <XalanTransformer/XalanTransformer.hpp>
23: #include <XalanTransformer/XalanParsedSource.hpp>
24: #include <XMLSupport/FormatterToXML.hpp>
25: #include <XMLSupport/FormatterToHTML.hpp>
26: #include <XMLSupport/FormatterToText.hpp>
27: #include <XMLSupport/FormatterTreeWalker.hpp>
28: #include <PlatformSupport/XalanFileOutputStream.hpp>
29: #include <PlatformSupport/XalanOutputStreamPrintWriter.hpp>
30: #include <PlatformSupport/DOMStringPrintWriter.hpp>
1.2 parser 31: #include <XalanDOM/XalanElement.hpp>
32: #include <XalanDOM/XalanNodeList.hpp>
1.1 parser 33:
34: // defines
35:
36: #define XDOC_CLASS_NAME "xdoc"
37:
38: #define XDOC_OUTPUT_METHOD_OPTION_NAME "method"
39: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_XML "xml"
40: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML "html"
41: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT "text"
42:
43: #define XDOC_OUTPUT_ENCODING_OPTION_NAME "encoding"
44:
45: #define XDOC_OUTPUT_DEFAULT_INDENT 4
46:
47: // class
48:
49: class MXdoc : public MXnode {
50: public: // VStateless_class
51: Value *create_new_value(Pool& pool) { return new(pool) VXdoc(pool); }
52:
53: public:
54: MXdoc(Pool& pool);
55:
56: public: // Methoded
57: bool used_directly() { return true; }
58: };
59:
60: // methods
61:
62: class ParserStringXalanOutputStream: public XalanOutputStream {
63: public:
64:
65: explicit ParserStringXalanOutputStream(String& astring) : fstring(astring) {}
66:
67: protected: // XalanOutputStream
68:
69: virtual void writeData(const char *theBuffer, unsigned long theBufferLength) {
70: char *copy=(char *)fstring.malloc((size_t)theBufferLength);
71: memcpy(copy, theBuffer, (size_t)theBufferLength);
1.2 parser 72: fstring.APPEND_CLEAN(copy, (size_t)theBufferLength, "xdoc", 0);
1.1 parser 73: }
74:
75: virtual void doFlush() {}
76:
77: private:
78:
79: String& fstring;
80:
81: };
82:
83: static void create_optioned_listener(
84: const char *& content_type, const char *& charset, FormatterListener *& listener,
85: Pool& pool,
86: const String& method_name, MethodParams *params, int index, Writer& writer) {
87: // default encoding from pool
88: const String *scharset=&pool.get_charset();
89: const String *method=0;
90: XalanDOMString xalan_encoding;
91:
92: if(params->size()>index) {
93: Value& voptions=params->as_no_junction(index, "options must not be code");
94: if(voptions.is_defined()) {
95: if(Hash *options=voptions.get_hash()) {
96: // $.method[xml|html|text]
97: if(Value *vmethod=static_cast<Value *>(options->get(*new(pool)
98: String(pool, XDOC_OUTPUT_METHOD_OPTION_NAME))))
99: method=&vmethod->as_string();
100:
101: // $.encoding[windows-1251|...]
102: if(Value *vencoding=static_cast<Value *>(options->get(*new(pool)
103: String(pool, XDOC_OUTPUT_ENCODING_OPTION_NAME)))) {
104: scharset=&vencoding->as_string();
105: }
106: } else
107: PTHROW(0, 0,
108: &method_name,
109: "options must be hash");
110: }
111: }
112:
113: xalan_encoding.append(charset=scharset->cstr());
114: if(!method/*default='xml'*/ || *method == XDOC_OUTPUT_METHOD_OPTION_VALUE_XML) {
115: content_type="text/xml";
116: listener=new FormatterToXML(writer,
117: XalanDOMString(), // version
118: true, // doIndent
119: XDOC_OUTPUT_DEFAULT_INDENT, // indent
120: xalan_encoding // encoding
121: );
122: } else if(*method == XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML) {
123: content_type="text/html";
124: listener=new FormatterToHTML(writer,
125: xalan_encoding, // encoding
126: XalanDOMString(), // mediaType
127: XalanDOMString(), // doctypeSystem; String to be printed at the top of the document
128: XalanDOMString(), // doctypePublic
129: true, // doIndent
130: XDOC_OUTPUT_DEFAULT_INDENT // indent
131: );
132: } else if(*method == XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT) {
133: content_type="text/plain";
134: listener=new FormatterToText(writer,
135: xalan_encoding // encoding
136: );
137: } else
138: PTHROW(0, 0,
139: method,
140: XDOC_OUTPUT_METHOD_OPTION_NAME " option is invalid; valid methods are: "
141: "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_XML "', "
142: "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML "', "
143: "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT "'");
144:
145: // never reached
146: }
147:
148: static void _save(Request& r, const String& method_name, MethodParams *params) {
149: Pool& pool=r.pool();
150: VXnode& vnode=*static_cast<VXnode *>(r.self);
151:
152: // filespec
153: const String& file_name=params->as_string(0, "file name must not be code");
154: const char *filespec=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
155:
156: // node
157: XalanNode& node=vnode.get_node(pool, &method_name);
158:
159: try {
160: XalanFileOutputStream stream(XalanDOMString(filespec, strlen(filespec)));
161: XalanOutputStreamPrintWriter writer(stream);
162: const char *content_type, *charset;
163: FormatterListener *formatterListener;
164: create_optioned_listener(content_type, charset, formatterListener,
165: pool, method_name, params, 1, writer);
166: FormatterTreeWalker treeWalker(*formatterListener);
167: treeWalker.traverse(&node); // Walk that node and produce the XML...
168: } catch(const XSLException& e) {
169: r._throw(&method_name, e);
170: }
171: }
172:
173: static void _string(Request& r, const String& method_name, MethodParams *params) {
174: Pool& pool=r.pool();
175: VXnode& vnode=*static_cast<VXnode *>(r.self);
176:
177: // node
178: XalanNode& node=vnode.get_node(pool, &method_name);
179:
180: try {
181: String parserString=*new(pool) String(pool);
182: ParserStringXalanOutputStream stream(parserString);
183: XalanOutputStreamPrintWriter writer(stream);
184: const char *content_type, *charset;
185: FormatterListener *formatterListener;
186: create_optioned_listener(content_type, charset, formatterListener,
187: pool, method_name, params, 0, writer);
188: FormatterTreeWalker treeWalker(*formatterListener);
189: treeWalker.traverse(&node); // Walk that node and produce the XML...
190:
191: // write out result
192: r.write_no_lang(parserString);
193: } catch(const XSLException& e) {
194: r._throw(&method_name, e);
195: }
196: }
197:
198:
199: static void _file(Request& r, const String& method_name, MethodParams *params) {
200: Pool& pool=r.pool();
201: VXnode& vnode=*static_cast<VXnode *>(r.self);
202:
203: // node
204: XalanNode& node=vnode.get_node(pool, &method_name);
205:
206: try {
207: String& parserString=*new(pool) String(pool);
208: ParserStringXalanOutputStream stream(parserString);
209: XalanOutputStreamPrintWriter writer(stream);
210: const char *content_type, *charset;
211: FormatterListener *formatterListener;
212: create_optioned_listener(content_type, charset, formatterListener,
213: pool, method_name, params, 0, writer);
214: FormatterTreeWalker treeWalker(*formatterListener);
215: treeWalker.traverse(&node); // Walk that node and produce the XML...
216:
217: // write out result
218: VFile& vfile=*new(pool) VFile(pool);
219: const char *cstr=parserString.cstr();
220: String *scontent_type=new(pool) String(pool, content_type);
221: Value *vcontent_type;
222: if(charset) {
223: VHash *vhcontent_type=new(pool) VHash(pool);
224: vhcontent_type->hash().put(*value_name, new(pool) VString(*scontent_type));
225: String *scharset=new(pool) String(pool, charset);
226: vhcontent_type->hash().put(*new(pool) String(pool, "charset"), new(pool) VString(*scharset));
227: vcontent_type=vhcontent_type;
228: } else
229: vcontent_type=new(pool) VString(*scontent_type);
230: vfile.set(false/*tainted*/, cstr, strlen(cstr), 0/*file_name*/, vcontent_type);
231: r.write_no_lang(vfile);
232: } catch(const XSLException& e) {
233: r._throw(&method_name, e);
234: }
235: }
236:
237: static void _set(Request& r, const String& method_name, MethodParams *params) {
238: Pool& pool=r.pool();
239: VXdoc& vdom=*static_cast<VXdoc *>(r.self);
240:
241: Value& vxml=params->as_junction(0, "xml must be code");
242: Temp_lang temp_lang(r, String::UL_XML);
243: const String& xml=r.process(vxml).as_string();
244:
245: std::istrstream stream(xml.cstr());
246: const XalanParsedSource* parsedSource;
247: int error=vdom.transformer().parseSource(&stream, parsedSource);
248:
249: if(error)
250: PTHROW(0, 0,
251: &method_name,
252: vdom.transformer().getLastError());
253:
254: // replace any previous parsed source
255: vdom.set_parsed_source(*parsedSource);
256: }
257:
258: static void _load(Request& r, const String& method_name, MethodParams *params) {
259: Pool& pool=r.pool();
260: VXdoc& vdom=*static_cast<VXdoc *>(r.self);
261:
262: // filespec
263: const String& file_name=params->as_string(0, "file name must not be code");
264: const char *filespec=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
265:
266: const XalanParsedSource* parsedSource;
267: int error=vdom.transformer().parseSource(filespec, parsedSource);
268:
269: if(error)
270: PTHROW(0, 0,
271: &file_name,
272: vdom.transformer().getLastError());
273:
274: // replace any previous parsed source
275: vdom.set_parsed_source(*parsedSource);
276: }
277:
278: static void add_xslt_param(const Hash::Key& aattribute, Hash::Val *ameaning,
279: void *info) {
280: XalanTransformer& transformer=*static_cast<XalanTransformer *>(info);
281: const char *attribute_cstr=aattribute.cstr();
282: const char *meaning_cstr=static_cast<Value *>(ameaning)->as_string().cstr();
283:
284: transformer.setStylesheetParam(
285: XalanDOMString(attribute_cstr),
286: XalanDOMString(meaning_cstr));
287: }
288: static void _xslt(Request& r, const String& method_name, MethodParams *params) {
289: Pool& pool=r.pool();
290: VXdoc& vdom=*static_cast<VXdoc *>(r.self);
291:
292: // params
293: if(params->size()>1) {
294: Value& vparams=params->as_no_junction(1, "transform parameters parameter must not be code");
295: if(vparams.is_defined())
296: if(Hash *params=vparams.get_hash())
297: params->for_each(add_xslt_param, &vdom.transformer());
298: else
299: PTHROW(0, 0,
300: &method_name,
301: "transform parameters parameter must be hash");
302: }
303:
304: // source
305: const XalanParsedSource &parsed_source=vdom.get_parsed_source(pool, &method_name);
306:
307: // stylesheet
308: const String& stylesheet_file_name=params->as_string(0, "file name must not be code");
309: const String& stylesheet_filespec=r.absolute(stylesheet_file_name);
310: //_asm int 3;
311: Stylesheet_connection& connection=XSLT_stylesheet_manager->get_connection(stylesheet_filespec);
312:
313: // target
314: XalanDocument* target=vdom.parser_liaison().createDocument();
315: XSLTResultTarget domResultTarget(target);
316:
317: // transform
318: int error=vdom.transformer().transform(
319: parsed_source,
320: &connection.stylesheet(),
321: domResultTarget);
322: connection.close();
323: if(error)
324: PTHROW(0, 0,
325: &stylesheet_file_name,
326: vdom.transformer().getLastError());
327:
328: // write out result
329: VXdoc& result=*new(pool) VXdoc(pool);
330: result.set_document(*target);
331: r.write_no_lang(result);
332: }
333:
1.2 parser 334: static void _getElementById(Request& r, const String& method_name, MethodParams *params) {
335: Pool& pool=r.pool();
336: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
337:
338: // elementId
339: const char *elementId=params->as_string(0, "elementID must not be code").cstr(String::UL_AS_IS);
340:
341: if(XalanElement *element=
342: vdoc.get_document(pool, &method_name).getElementById(XalanDOMString(elementId))) {
343: // write out result
344: VXnode& result=*new(pool) VXnode(pool, element);
345: r.write_no_lang(result);
346: }
347: }
348:
349: static void _getElementsByTagName(Request& r, const String& method_name, MethodParams *params) {
350: Pool& pool=r.pool();
351: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
352:
353: // tagname
354: const char *tagname=params->as_string(0, "tagname must not be code").cstr(String::UL_AS_IS);
355:
356: VHash& result=*new(pool) VHash(pool);
357: if(const XalanNodeList *nodes=
358: vdoc.get_document(pool, &method_name).getElementsByTagName(XalanDOMString(tagname))) {
359: for(int i=0; i<nodes->getLength(); i++) {
360: String& skey=*new(pool) String(pool);
361: {
362: char *buf=(char *)pool.malloc(MAX_NUMBER);
363: snprintf(buf, MAX_NUMBER, "%d", i);
364: skey << buf;
365: }
366:
367: result.hash().put(skey, new(pool) VXnode(pool, nodes->item(i)));
368: }
369: }
370:
371: // write out result
372: r.write_no_lang(result);
373: }
374:
375: static void _getElementsByTagNameNS(Request& r, const String& method_name, MethodParams *params) {
376: Pool& pool=r.pool();
377: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
378:
379: // namespaceURI;localName
380: const char *namespaceURI=params->as_string(0, "namespaceURI must not be code").cstr(String::UL_AS_IS);
381: const char *localName=params->as_string(0, "localName must not be code").cstr(String::UL_AS_IS);
382:
383: VHash& result=*new(pool) VHash(pool);
384: if(const XalanNodeList *nodes=
385: vdoc.get_document(pool, &method_name).getElementsByTagNameNS(
386: XalanDOMString(namespaceURI), XalanDOMString(localName))) {
387: for(int i=0; i<nodes->getLength(); i++) {
388: String& skey=*new(pool) String(pool);
389: {
390: char *buf=(char *)pool.malloc(MAX_NUMBER);
391: snprintf(buf, MAX_NUMBER, "%d", i);
392: skey << buf;
393: }
394:
395: result.hash().put(skey, new(pool) VXnode(pool, nodes->item(i)));
396: }
397: }
398:
399: // write out result
400: r.write_no_lang(result);
401: }
402:
1.1 parser 403: // constructor
404:
405: MXdoc::MXdoc(Pool& apool) : MXnode(apool) {
406: set_name(*NEW String(pool(), XDOC_CLASS_NAME));
407:
1.2 parser 408: // ^xdoc.save[some.xml]
409: // ^xdoc.save[some.xml;options hash]
1.1 parser 410: add_native_method("save", Method::CT_DYNAMIC, _save, 1, 2);
411:
1.2 parser 412: // ^xdoc.string[] <doc/>
413: // ^xdoc.string[options hash] <doc/>
1.1 parser 414: add_native_method("string", Method::CT_DYNAMIC, _string, 0, 1);
415:
1.2 parser 416: // ^xdoc.file[] file with "<doc/>"
417: // ^xdoc.file[options hash] file with "<doc/>"
1.1 parser 418: add_native_method("file", Method::CT_DYNAMIC, _file, 0, 1);
419:
1.2 parser 420: // ^xdoc::set[<some>xml</some>]
1.1 parser 421: add_native_method("set", Method::CT_DYNAMIC, _set, 1, 1);
422:
1.2 parser 423: // ^xdoc::load[some.xml]
1.1 parser 424: add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
425:
1.2 parser 426: // ^xdoc.xslt[stylesheet file_name]
427: // ^xdoc.xslt[stylesheet file_name;params hash]
1.1 parser 428: add_native_method("xslt", Method::CT_DYNAMIC, _xslt, 1, 2);
1.2 parser 429:
430: // ^xdoc.getElementById[elementId]
431: add_native_method("getElementById", Method::CT_DYNAMIC, _getElementById, 1, 1);
432:
1.3 ! parser 433: // ^xdoc.getElementsByTagName[tagname]
1.2 parser 434: add_native_method("getElementsByTagName", Method::CT_DYNAMIC, _getElementsByTagName, 1, 1);
435:
436: // ^xdoc.getElementsByTagNameNS[namespaceURI;localName] = array of nodes
437: add_native_method("getElementsByTagNameNS", Method::CT_DYNAMIC, _getElementsByTagNameNS, 2, 2);
1.1 parser 438:
439: }
440: // global variable
441:
442: Methoded *Xdoc_class;
443:
444: // creator
445:
446: #endif
447:
448: Methoded *MXdoc_create(Pool& pool) {
449: return
450: #ifdef XML
451: Xdoc_class=new(pool) MXdoc(pool);
452: #else
453: 0
454: #endif
455: ;
456: }
E-mail: