1 /*
2 * Copyright (C) 2001-2003 Peter J Jones (pjones@pmade.org)
3 * All Rights Reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * 3. Neither the name of the Author nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * $Id: stylesheet.cpp 543412 2017-08-09 18:22:55Z satskyse $
35 * NOTE: This file was modified from its original version 0.6.0
36 * to fit the NCBI C++ Toolkit build framework and
37 * API and functionality requirements.
38 */
39
40 /** @file
41 * This file contains the implementation of the xslt::stylesheet class.
42 **/
43
44 // xmlwrapp includes
45 #include <misc/xmlwrapp/stylesheet.hpp>
46 #include <misc/xmlwrapp/document.hpp>
47 #include <misc/xmlwrapp/exception.hpp>
48 #include <misc/xmlwrapp/xslt_exception.hpp>
49
50 #include "utility.hpp"
51 #include "document_impl.hpp"
52
53 // libxslt includes
54 #include <libxslt/xslt.h>
55 #include <libxslt/xsltInternals.h>
56 #include <libxslt/transform.h>
57 #include <libxslt/xsltutils.h>
58 #include <libxslt/extensions.h>
59 #include <libxml/xpath.h>
60 #include <libxml/xpathInternals.h>
61
62 // standard includes
63 #include <stdexcept>
64 #include <memory>
65 #include <string>
66 #include <vector>
67 #include <map>
68 #include <string.h>
69
70 #include "extension_function_impl.hpp"
71 #include "extension_element_impl.hpp"
72
73 #include "stylesheet_impl.hpp"
74 #include "https_input_impl.hpp"
75
76
77 namespace xslt {
78 namespace impl {
is_xml_output_method(xsltStylesheetPtr ss)79 bool is_xml_output_method (xsltStylesheetPtr ss)
80 {
81 if (ss->method == NULL)
82 return true;
83 return strcmp(reinterpret_cast<const char *>(ss->method),
84 "xml") == 0;
85 }
86
destroy_stylesheet(xsltStylesheetPtr ss)87 void destroy_stylesheet (xsltStylesheetPtr ss)
88 {
89 if (ss->_private == NULL)
90 xsltFreeStylesheet(ss);
91 else {
92 stylesheet_refcount * ss_rc =
93 static_cast<stylesheet_refcount *>(ss->_private);
94 if (ss_rc->dec_ref() == 0) {
95 delete ss_rc;
96 xsltFreeStylesheet(ss);
97 }
98 }
99 }
100
save_to_string(xmlDocPtr doc,xsltStylesheetPtr ss,std::string & s)101 void save_to_string(xmlDocPtr doc,
102 xsltStylesheetPtr ss,
103 std::string & s)
104 {
105 xmlChar * xml_string;
106 int xml_string_length;
107
108 if (xsltSaveResultToString(&xml_string,
109 &xml_string_length, doc, ss) >= 0)
110 {
111 xml::impl::xmlchar_helper helper(xml_string);
112 if (xml_string_length)
113 s.assign(helper.get(), xml_string_length);
114 }
115 }
116
117 bool
save_to_file(xmlDocPtr doc,xsltStylesheetPtr ss,const char * filename,int)118 save_to_file(xmlDocPtr doc,
119 xsltStylesheetPtr ss,
120 const char * filename,
121 int /* compression_level */)
122 {
123 return xsltSaveResultToFilename(filename, doc, ss, 0) >= 0;
124 }
125 } // End of impl namespace
126 } // End of xslt namespace
127
128
clear_nodes(void)129 void xslt::impl::stylesheet_impl::clear_nodes (void)
130 {
131 for (std::vector<xmlNodePtr>::const_iterator k = nodes_to_free_.begin();
132 k != nodes_to_free_.end(); ++k)
133 xmlFreeNode(*k);
134 nodes_to_free_.clear();
135 }
136
137
138 extern "C" {
139
140 // XSLT extension function callback
xslt_ext_func_cb(void * c,int arg_num)141 void xslt_ext_func_cb(void *c, int arg_num)
142 {
143 xmlXPathParserContext * ctxt =
144 reinterpret_cast<xmlXPathParserContext *>(c);
145 xsltTransformContextPtr xslt_ctxt =
146 xsltXPathGetTransformContext(ctxt);
147 xslt::impl::stylesheet_impl * s_impl =
148 reinterpret_cast<xslt::impl::stylesheet_impl *>(
149 xslt_ctxt->_private);
150 xmlNodePtr current_node = ctxt->context->node;
151 xmlDocPtr current_doc = ctxt->context->doc;
152
153 // Search for a registered extension function
154 ext_func_key key;
155 key.first = reinterpret_cast<const char *>(ctxt->context->function);
156 if (ctxt->context->functionURI != NULL)
157 key.second = reinterpret_cast<const char *>(
158 ctxt->context->functionURI);
159
160 ext_funcs_map_type::iterator found = s_impl->ext_functions_.find(key);
161 if (found == s_impl->ext_functions_.end())
162 return; // No extension function were found
163
164 // The corresponding extension function has been found.
165 // Prepare parameters and call it
166 std::vector<xslt::xpath_object> args;
167 xml::node node;
168 xml::document doc;
169
170 // Prepare arguments for the extension function call. Arguments are
171 // coming in the reverse order.
172 args.reserve(arg_num);
173 for (int k = 0; k < arg_num; ++k) {
174 xmlXPathObjectPtr current_arg = valuePop(ctxt);
175
176 args.insert(args.begin(),
177 xslt::xpath_object(reinterpret_cast<void*>(current_arg)));
178 args[0].set_from_xslt();
179 }
180
181
182 // Wrap libxml2 data with xmlwrapp and make sure that xmlwrapp does NOT
183 // have ownership on the node and the document.
184 node.set_node_data(current_node);
185 doc.set_doc_data(current_doc);
186 doc.pimpl_->set_ownership(false);
187
188 // Set the context to make error reporting and setting retval
189 // working properly
190 found->second.first->pimpl_->xpath_parser_ctxt = ctxt;
191
192 // Make a call
193 try {
194 found->second.first->execute(args, node, doc);
195 } catch (const std::exception & ex) {
196 std::string error("Exception in the user extension function '" +
197 key.first + "': " + std::string(ex.what()));
198 found->second.first->report_error(error.c_str());
199 } catch (...) {
200 std::string error("Unknown exception in the user "
201 "extension function '" + key.first + "'");
202 found->second.first->report_error(error.c_str());
203 }
204
205 // Clear the context
206 found->second.first->pimpl_->xpath_parser_ctxt = NULL;
207
208 return;
209 }
210
211 // XSLT extension element callback
xslt_ext_element_cb(void * c,void * input_node_,void * instruction_node_,void * compiled_stylesheet_info)212 void xslt_ext_element_cb(void *c, void *input_node_,
213 void *instruction_node_,
214 void *compiled_stylesheet_info)
215 {
216 xsltTransformContextPtr xslt_ctxt =
217 reinterpret_cast<xsltTransformContextPtr>(c);
218 xmlNodePtr instruction_node =
219 reinterpret_cast<xmlNodePtr>(instruction_node_);
220 xslt::impl::stylesheet_impl * s_impl =
221 reinterpret_cast<xslt::impl::stylesheet_impl *>(
222 xslt_ctxt->_private);
223
224 ext_elem_key key;
225 key.first = reinterpret_cast<const char *>(instruction_node->name);
226 if (instruction_node->ns != NULL && instruction_node->ns->href != NULL)
227 key.second =
228 reinterpret_cast<const char *>(instruction_node->ns->href);
229
230 ext_elems_map_type::iterator found = s_impl->ext_elements_.find(key);
231 if (found == s_impl->ext_elements_.end())
232 return; // No extension element were found
233
234 // The corresponding extension element has been found.
235 // Prepare the parameters.
236 xmlNodePtr input_node =
237 reinterpret_cast<xmlNodePtr>(input_node_);
238
239 xml::node inp_node;
240 xml::node instr_node;
241 xml::node insert_node;
242 xml::document doc;
243
244 // Wrap libxml2 data with xmlwrapp and make sure that xmlwrapp does NOT
245 // have ownership on the nodes and the document.
246 inp_node.set_node_data(input_node);
247 instr_node.set_node_data(instruction_node);
248 insert_node.set_node_data(xslt_ctxt->insert);
249 doc.set_doc_data(xslt_ctxt->xpathCtxt->doc);
250 doc.pimpl_->set_ownership(false);
251
252 // Set the context to make error reporting working properly
253 found->second.first->pimpl_->xslt_ctxt = xslt_ctxt;
254 found->second.first->pimpl_->instruction_node = instruction_node;
255
256 // Make a call
257 try {
258 found->second.first->process(inp_node, instr_node,
259 insert_node, doc);
260 } catch (const std::exception & ex) {
261 std::string error("Exception in the user extension element '" +
262 key.first + "': " +
263 std::string(ex.what()));
264 found->second.first->report_error(error.c_str());
265 } catch (...) {
266 std::string error("Unknown error in the user "
267 "extension element '" +
268 key.first + "'");
269 found->second.first->report_error(error.c_str());
270 }
271
272 // Clear the context
273 found->second.first->pimpl_->xslt_ctxt = NULL;
274 found->second.first->pimpl_->instruction_node = NULL;
275
276 return;
277 }
278
279 } // extern "C"
280
281
282 namespace
283 {
284
make_vector_param(std::vector<const char * > & v,const xslt::stylesheet::param_type & p)285 void make_vector_param(std::vector<const char*> &v,
286 const xslt::stylesheet::param_type &p)
287 {
288 v.reserve(p.size());
289
290 xslt::stylesheet::param_type::const_iterator i = p.begin(), end = p.end();
291 for (; i != end; ++i)
292 {
293 v.push_back(i->first.c_str());
294 v.push_back(i->second.c_str());
295 }
296
297 v.push_back(static_cast<const char*>(0));
298 }
299
300
301 extern "C"
302 {
303
error_cb(void * c,const char * message,...)304 static void error_cb(void *c, const char *message, ...)
305 {
306 xsltTransformContextPtr ctxt = static_cast<xsltTransformContextPtr>(c);
307 xslt::impl::stylesheet_impl *s_impl =
308 static_cast<xslt::impl::stylesheet_impl*>(ctxt->_private);
309
310 // tell the processor to stop when it gets a chance:
311 if ( ctxt->state == XSLT_STATE_OK )
312 ctxt->state = XSLT_STATE_STOPPED;
313
314 // concatenate all error messages:
315 if ( s_impl->errors_occured_ )
316 s_impl->error_.append("\n");
317 s_impl->errors_occured_ = true;
318
319 std::string formatted;
320
321 va_list ap;
322 va_start(ap, message);
323 xml::impl::printf2string(formatted, message, ap);
324 va_end(ap);
325
326 s_impl->error_.append(formatted);
327
328 if (s_impl->messages_ != NULL) {
329 // Need to insert the error information into the user provided container
330 int line = 0;
331 std::string filename;
332
333 // Supposedly the current served node
334 xmlNodePtr node = ctxt->inst;
335 if (node != NULL) {
336 if ((node->type == XML_DOCUMENT_NODE) ||
337 (node->type == XML_HTML_DOCUMENT_NODE)) {
338 xmlDocPtr d = (xmlDocPtr) node;
339 if (d->URL != NULL)
340 filename = reinterpret_cast<const char *>(d->URL);
341 } else {
342 line = xmlGetLineNo(node);
343 if (node->doc != NULL)
344 if (node->doc->URL != NULL)
345 filename = reinterpret_cast<const char*>(node->doc->URL);
346 }
347 }
348
349 s_impl->messages_->get_messages().push_back(
350 xml::error_message(
351 formatted,
352 xml::error_message::type_error,
353 line, filename));
354 }
355 }
356
357 } // extern "C"
358
359
360
apply_stylesheet(xslt::impl::stylesheet_impl * s_impl,xmlDocPtr doc,const xslt::stylesheet::param_type * p=NULL,xml::error_messages * messages_=NULL)361 xmlDocPtr apply_stylesheet(xslt::impl::stylesheet_impl *s_impl,
362 xmlDocPtr doc,
363 const xslt::stylesheet::param_type *p = NULL,
364 xml::error_messages * messages_ = NULL
365 )
366 {
367 xsltStylesheetPtr style = s_impl->ss_;
368
369 std::vector<const char*> v;
370 if (p)
371 make_vector_param(v, *p);
372
373 xsltTransformContextPtr ctxt = xsltNewTransformContext(style, doc);
374 ctxt->_private = s_impl;
375 xsltSetTransformErrorFunc(ctxt, ctxt, error_cb);
376
377 // Register extension functions
378 for (ext_funcs_map_type::iterator k = s_impl->ext_functions_.begin();
379 k != s_impl->ext_functions_.end(); ++k) {
380 if (xsltRegisterExtFunction(
381 ctxt,
382 reinterpret_cast<const xmlChar*>(k->first.first.c_str()),
383 reinterpret_cast<const xmlChar*>(k->first.second.c_str()),
384 reinterpret_cast<xmlXPathFunction>(xslt_ext_func_cb)) != 0) {
385 xsltFreeTransformContext(ctxt);
386 throw xslt::exception("Error registering extension function " +
387 k->first.first);
388 }
389 }
390
391 // Register extension elements
392 for (ext_elems_map_type::iterator k = s_impl->ext_elements_.begin();
393 k != s_impl->ext_elements_.end(); ++k) {
394 if (xsltRegisterExtElement(
395 ctxt,
396 reinterpret_cast<const xmlChar*>(k->first.first.c_str()),
397 reinterpret_cast<const xmlChar*>(k->first.second.c_str()),
398 reinterpret_cast<xsltTransformFunction>
399 (xslt_ext_element_cb)) != 0) {
400 xsltFreeTransformContext(ctxt);
401 throw xslt::exception("Error registering extension element " +
402 k->first.first);
403 }
404 }
405
406 // clear the error flag before applying the stylesheet
407 s_impl->errors_occured_ = false;
408 s_impl->messages_ = messages_;
409
410 // Wierd way to collect https warnings: via tls in the custom IO handler
411 // See https_input_impl.*
412 if (s_impl->messages_)
413 xml::impl::clear_https_messages();
414 xmlDocPtr result =
415 xsltApplyStylesheetUser(style, doc, p ? &v[0] : 0, NULL, NULL, ctxt);
416 if (s_impl->messages_)
417 xml::impl::collect_https_messages(*s_impl->messages_);
418
419 // This is a part of a hack of leak-less handling nodeset return values
420 // from XSLT extension functions. XSLT frees nodes in a nodeset too early
421 // so the boolval is not set to 1 to free them automatically. Instead the
422 // nodes are memorized in a vector. These nodes are freed here, i.e. when
423 // the transformation is completed.
424 // See extension_function.cpp and xpath_object.cpp as well.
425 s_impl->clear_nodes();
426
427 xsltFreeTransformContext(ctxt);
428
429 // it's possible there was an error that didn't prevent creation of some
430 // (incorrect) document
431 if ( result && s_impl->errors_occured_ )
432 {
433 xmlFreeDoc(result);
434 return NULL;
435 }
436
437 if ( !result )
438 {
439 // set generic error message if nothing more specific is known
440 if ( s_impl->error_.empty() )
441 s_impl->error_ = "unknown XSLT transformation error";
442 return NULL;
443 }
444
445 return result;
446 }
447
448 } // end of anonymous namespace
449
450
attach_refcount(void)451 void xslt::stylesheet::attach_refcount(void)
452 {
453 impl::stylesheet_refcount * refcount;
454 try {
455 refcount = new impl::stylesheet_refcount;
456 } catch (...) {
457 xsltFreeStylesheet(pimpl_->ss_);
458 throw;
459 }
460 refcount->inc_ref();
461 pimpl_->ss_->_private = refcount;
462 }
463
464
stylesheet(const char * filename)465 xslt::stylesheet::stylesheet(const char *filename)
466 {
467 if (!filename)
468 throw xslt::exception("invalid file name");
469
470 std::unique_ptr<impl::stylesheet_impl>
471 ap(pimpl_ = new impl::stylesheet_impl);
472 xml::error_messages msgs;
473 xml::document doc(filename, &msgs, xml::type_warnings_not_errors);
474 xmlDocPtr xmldoc = static_cast<xmlDocPtr>(doc.get_doc_data());
475
476 if ( (pimpl_->ss_ = xsltParseStylesheetDoc(xmldoc)) == 0)
477 {
478 // TODO error_ can't get set yet. Need changes from libxslt first
479 if (pimpl_->error_.empty())
480 pimpl_->error_ = "unknown XSLT parser error";
481
482 msgs.get_messages().push_back(xml::error_message(
483 pimpl_->error_,
484 xml::error_message::type_error,
485 0, filename));
486 throw xml::parser_exception(msgs);
487 }
488
489 attach_refcount();
490
491 // if we got this far, the xmldoc we gave to xsltParseStylesheetDoc is
492 // now owned by the stylesheet and will be cleaned up in our destructor.
493 doc.release_doc_data();
494 ap.release();
495 }
496
497
stylesheet(const xml::document & doc)498 xslt::stylesheet::stylesheet(const xml::document & doc)
499 {
500 xml::document doc_copy(doc); /* NCBI_FAKE_WARNING */
501 xmlDocPtr xmldoc = static_cast<xmlDocPtr>(
502 doc_copy.get_doc_data());
503 std::unique_ptr<impl::stylesheet_impl>
504 ap(pimpl_ = new impl::stylesheet_impl);
505
506 if ( (pimpl_->ss_ = xsltParseStylesheetDoc(xmldoc)) == 0)
507 {
508 // TODO error_ can't get set yet. Need changes from libxslt first
509 if (pimpl_->error_.empty())
510 pimpl_->error_ = "unknown XSLT parser error";
511
512 xml::error_messages messages;
513 messages.get_messages().push_back(xml::error_message(
514 pimpl_->error_,
515 xml::error_message::type_error,
516 0, ""));
517 throw xml::parser_exception(messages);
518 }
519
520 attach_refcount();
521
522 // if we got this far, the xmldoc we gave to xsltParseStylesheetDoc is
523 // now owned by the stylesheet and will be cleaned up in our destructor.
524 doc_copy.release_doc_data();
525 ap.release();
526 }
527
528
stylesheet(const char * data,size_t size)529 xslt::stylesheet::stylesheet (const char* data, size_t size)
530 {
531 std::unique_ptr<impl::stylesheet_impl>
532 ap(pimpl_ = new impl::stylesheet_impl);
533 xml::error_messages msgs;
534 xml::document doc(data, size, &msgs,
535 xml::type_warnings_not_errors);
536 xmlDocPtr xmldoc = static_cast<xmlDocPtr>(doc.get_doc_data());
537
538 if ( (pimpl_->ss_ = xsltParseStylesheetDoc(xmldoc)) == 0)
539 {
540 // TODO error_ can't get set yet. Need changes from libxslt first
541 if (pimpl_->error_.empty())
542 pimpl_->error_ = "unknown XSLT parser error";
543
544 msgs.get_messages().push_back(xml::error_message(
545 pimpl_->error_,
546 xml::error_message::type_error,
547 0, ""));
548 throw xml::parser_exception(msgs);
549 }
550
551 attach_refcount();
552
553 // if we got this far, the xmldoc we gave to xsltParseStylesheetDoc is
554 // now owned by the stylesheet and will be cleaned up in our destructor.
555 doc.release_doc_data();
556 ap.release();
557 }
558
559
stylesheet(std::istream & stream)560 xslt::stylesheet::stylesheet (std::istream & stream)
561 {
562 std::unique_ptr<impl::stylesheet_impl>
563 ap(pimpl_ = new impl::stylesheet_impl);
564 xml::error_messages msgs;
565 xml::document doc(stream, &msgs, xml::type_warnings_not_errors);
566 xmlDocPtr xmldoc = static_cast<xmlDocPtr>(doc.get_doc_data());
567
568 if ( (pimpl_->ss_ = xsltParseStylesheetDoc(xmldoc)) == 0)
569 {
570 // TODO error_ can't get set yet. Need changes from libxslt first
571 if (pimpl_->error_.empty())
572 pimpl_->error_ = "unknown XSLT parser error";
573
574 msgs.get_messages().push_back(xml::error_message(
575 pimpl_->error_,
576 xml::error_message::type_error,
577 0, ""));
578 throw xml::parser_exception(msgs);
579 }
580
581 attach_refcount();
582
583 // if we got this far, the xmldoc we gave to xsltParseStylesheetDoc is
584 // now owned by the stylesheet and will be cleaned up in our destructor.
585 doc.release_doc_data();
586 ap.release();
587 }
588
589
590 void
register_extension_function(extension_function * ef,const char * name,const char * uri,xml::ownership_type ownership)591 xslt::stylesheet::register_extension_function (extension_function * ef,
592 const char * name,
593 const char * uri,
594 xml::ownership_type ownership)
595 {
596 if (name == NULL) {
597 if (ownership == xml::type_own)
598 delete ef;
599 throw xslt::exception("Extension function name is uninitialised");
600 }
601
602 if (uri == NULL) {
603 if (ownership == xml::type_own)
604 delete ef;
605 throw xslt::exception("Extension function URI is uninitialised");
606 }
607
608 ext_func_key key = std::pair<std::string,
609 std::string>(name, uri);
610 ext_funcs_map_type::iterator found(pimpl_->ext_functions_.find(key));
611
612 if (found != pimpl_->ext_functions_.end()) {
613 if (found->second.second == xml::type_own)
614 delete found->second.first;
615 }
616
617 pimpl_->ext_functions_[ key ] = std::pair<extension_function *,
618 xml::ownership_type>(ef, ownership);
619 return;
620 }
621
622
623 void
register_extension_element(extension_element * ee,const char * name,const char * uri,xml::ownership_type ownership)624 xslt::stylesheet::register_extension_element (extension_element * ee,
625 const char * name,
626 const char * uri,
627 xml::ownership_type ownership)
628 {
629 if (name == NULL) {
630 if (ownership == xml::type_own)
631 delete ee;
632 throw xslt::exception("Extension element name is uninitialised");
633 }
634
635 if (uri == NULL) {
636 if (ownership == xml::type_own)
637 delete ee;
638 throw xslt::exception("Extension element URI is uninitialised");
639 }
640
641 ext_elem_key key = std::pair<std::string,
642 std::string>(name, uri);
643 ext_elems_map_type::iterator found(pimpl_->ext_elements_.find(key));
644
645 if (found != pimpl_->ext_elements_.end()) {
646 if (found->second.second == xml::type_own)
647 delete found->second.first;
648 }
649
650 pimpl_->ext_elements_[ key ] = std::pair<extension_element *,
651 xml::ownership_type>(ee, ownership);
652 return;
653 }
654
655
destroy(void)656 void xslt::stylesheet::destroy(void)
657 {
658 if (pimpl_ != NULL) {
659 // Delete extension functions we owe
660 for (ext_funcs_map_type::iterator k = pimpl_->ext_functions_.begin();
661 k != pimpl_->ext_functions_.end(); ++k) {
662 if (k->second.second == xml::type_own)
663 delete k->second.first;
664 }
665
666 // Delete extension elements we owe
667 for (ext_elems_map_type::iterator k = pimpl_->ext_elements_.begin();
668 k != pimpl_->ext_elements_.end(); ++k) {
669 if (k->second.second == xml::type_own)
670 delete k->second.first;
671 }
672
673 if (pimpl_->ss_)
674 xslt::impl::destroy_stylesheet(pimpl_->ss_);
675 delete pimpl_;
676 }
677 }
678
679
~stylesheet()680 xslt::stylesheet::~stylesheet()
681 {
682 destroy();
683 }
684
685
stylesheet(stylesheet && other)686 xslt::stylesheet::stylesheet (stylesheet && other) :
687 pimpl_(other.pimpl_)
688 {
689 other.pimpl_ = NULL;
690 }
691
692
operator =(stylesheet && other)693 xslt::stylesheet & xslt::stylesheet::operator= (stylesheet && other)
694 {
695 if (this != &other) {
696 destroy();
697 pimpl_ = other.pimpl_;
698 other.pimpl_ = NULL;
699 }
700 return *this;
701 }
702
703
apply(const xml::document & doc,xml::error_messages * messages_)704 xml::document_proxy xslt::stylesheet::apply (const xml::document &doc,
705 xml::error_messages * messages_)
706 {
707 xmlDocPtr input = static_cast<xmlDocPtr>(doc.get_doc_data_read_only());
708 xmlDocPtr xmldoc = apply_stylesheet(pimpl_, input, NULL, messages_);
709
710 if ( !xmldoc )
711 throw xslt::exception(pimpl_->error_);
712
713 return xml::document_proxy(xmldoc, pimpl_->ss_);
714 }
715
716
apply(const xml::document & doc,const param_type & with_params,xml::error_messages * messages_)717 xml::document_proxy xslt::stylesheet::apply (const xml::document &doc,
718 const param_type &with_params,
719 xml::error_messages * messages_ )
720 {
721 xmlDocPtr input = static_cast<xmlDocPtr>(doc.get_doc_data_read_only());
722 xmlDocPtr xmldoc = apply_stylesheet(pimpl_, input, &with_params, messages_);
723
724 if ( !xmldoc )
725 throw xslt::exception(pimpl_->error_);
726
727 return xml::document_proxy(xmldoc, pimpl_->ss_);
728 }
729
730