Class: Nokogiri::XSLT::Stylesheet
- Inherits:
-
Object
- Object
- Nokogiri::XSLT::Stylesheet
- Defined in:
- lib/nokogiri/xslt/stylesheet.rb,
ext/nokogiri/xslt_stylesheet.c
Overview
A Stylesheet represents an XSLT Stylesheet object. Stylesheet creation is done through Nokogiri::XSLT.parse (or the convenience method Nokogiri.XSLT). Here is an example of transforming an XML::Document with a Stylesheet:
doc = Nokogiri::XML(File.read('some_file.xml'))
xslt = Nokogiri::XSLT(File.read('some_transformer.xslt'))
xslt.transform(doc) # => Nokogiri::XML::Document
🛡 This class does not support execution of untrusted stylesheets. An untrusted stylesheet may consume a large amount of CPU, memory, or other system resources during transformation, and IO and file access are not restricted. See Nokogiri::XSLT for more information about the security implications of untrusted stylesheets.
Many XSLT transformations include serialization behavior to emit a non-XML document. For these cases, please take care to invoke the #serialize method on the result of the transformation:
doc = Nokogiri::XML(File.read('some_file.xml'))
xslt = Nokogiri::XSLT(File.read('some_transformer.xslt'))
xslt.serialize(xslt.transform(doc)) # => String
or use the #apply_to method, which is a shortcut for serialize(transform(document)):
doc = Nokogiri::XML(File.read('some_file.xml'))
xslt = Nokogiri::XSLT(File.read('some_transformer.xslt'))
xslt.apply_to(doc) # => String
See Nokogiri::XSLT::Stylesheet#transform for more information and examples.
Class Method Summary collapse
-
.parse_stylesheet_doc(document) ⇒ Object
Parse an XSLT::Stylesheet from
document.
Instance Method Summary collapse
-
#apply_to(document, params = []) ⇒ Object
:call-seq: apply_to(document, params = []) -> String.
-
#serialize(document) ⇒ Object
Serialize
documentto an xml string, as specified by themethodparameter in the Stylesheet. -
#transform(*args) ⇒ Object
Transform an XML::Document as defined by an XSLT::Stylesheet.
Class Method Details
.parse_stylesheet_doc(document) ⇒ Object
Parse an XSLT::Stylesheet from document.
[Parameters]
document(Nokogiri::XML::Document) the document to be parsed.
[Returns] Nokogiri::XSLT::Stylesheet
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'ext/nokogiri/xslt_stylesheet.c', line 81
static VALUE
parse_stylesheet_doc(VALUE klass, VALUE xmldocobj)
{
xmlDocPtr xml, xml_cpy;
VALUE errstr, exception;
xsltStylesheetPtr ss ;
xml = noko_xml_document_unwrap(xmldocobj);
errstr = rb_str_new(0, 0);
xsltSetGenericErrorFunc((void *)errstr, xslt_generic_error_handler);
xml_cpy = xmlCopyDoc(xml, 1); /* 1 => recursive */
ss = xsltParseStylesheetDoc(xml_cpy);
xsltSetGenericErrorFunc(NULL, NULL);
if (!ss) {
xmlFreeDoc(xml_cpy);
exception = rb_exc_new3(rb_eRuntimeError, errstr);
rb_exc_raise(exception);
}
return Nokogiri_wrap_xslt_stylesheet(ss);
}
|
Instance Method Details
#apply_to(document, params = []) ⇒ Object
:call-seq:
apply_to(document, params = []) -> String
Apply an XSLT stylesheet to an XML::Document and serialize it properly. This method is equivalent to calling #serialize on the result of #transform.
[Parameters]
documentis an instance of XML::Document to transformparamsis an array of strings used as XSLT parameters, passed into #transform
[Returns] A string containing the serialized result of the transformation.
See Nokogiri::XSLT::Stylesheet#transform for more information and examples.
49 50 51 |
# File 'lib/nokogiri/xslt/stylesheet.rb', line 49 def apply_to(document, params = []) serialize(transform(document, params)) end |
#serialize(document) ⇒ Object
Serialize document to an xml string, as specified by the method parameter in the Stylesheet.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'ext/nokogiri/xslt_stylesheet.c', line 114
static VALUE
rb_xslt_stylesheet_serialize(VALUE self, VALUE xmlobj)
{
xmlDocPtr xml ;
nokogiriXsltStylesheetTuple *wrapper;
xmlChar *doc_ptr ;
int doc_len ;
VALUE rval ;
xml = noko_xml_document_unwrap(xmlobj);
TypedData_Get_Struct(
self,
nokogiriXsltStylesheetTuple,
&nokogiri_xslt_stylesheet_tuple_type,
wrapper
);
xsltSaveResultToString(&doc_ptr, &doc_len, xml, wrapper->ss);
rval = NOKOGIRI_STR_NEW(doc_ptr, doc_len);
xmlFree(doc_ptr);
return rval ;
}
|
#transform(document) ⇒ Object #transform(document, params = {}) ⇒ Object
Transform an XML::Document as defined by an XSLT::Stylesheet.
[Parameters]
document(Nokogiri::XML::Document) the document to be transformed.params(Hash, Array) strings used as XSLT parameters.
[Returns] Nokogiri::XML::Document
Example of basic transformation:
xslt = <<~XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="title"/>
<xsl:template match="/">
<html>
<body>
<h1><xsl:value-of select="$title"/></h1>
<ol>
<xsl:for-each select="staff/employee">
<li><xsl:value-of select="employeeId"></li>
</xsl:for-each>
</ol>
</body>
</html>
</xsl:stylesheet>
XSLT
xml = <<~XML
<?xml version="1.0"?>
<staff>
<employee>
<employeeId>EMP0001</employeeId>
<position>Accountant</position>
</employee>
<employee>
<employeeId>EMP0002</employeeId>
<position>Developer</position>
</employee>
</staff>
XML
doc = Nokogiri::XML::Document.parse(xml)
stylesheet = Nokogiri::XSLT.parse(xslt)
⚠ Note that the h1 element is empty because no param has been provided!
stylesheet.transform(doc).to_xml
# => "<html><body>\n" +
# "<h1></h1>\n" +
# "<ol>\n" +
# "<li>EMP0001</li>\n" +
# "<li>EMP0002</li>\n" +
# "</ol>\n" +
# "</body></html>\n"
Example of using an input parameter hash:
⚠ The title is populated, but note how we need to quote-escape the value.
stylesheet.transform(doc, { "title" => "'Employee List'" }).to_xml
# => "<html><body>\n" +
# "<h1>Employee List</h1>\n" +
# "<ol>\n" +
# "<li>EMP0001</li>\n" +
# "<li>EMP0002</li>\n" +
# "</ol>\n" +
# "</body></html>\n"
Example using the XSLT.quote_params helper method to safely quote-escape strings:
stylesheet.transform(doc, Nokogiri::XSLT.quote_params({ "title" => "Aaron's List" })).to_xml
# => "<html><body>\n" +
# "<h1>Aaron's List</h1>\n" +
# "<ol>\n" +
# "<li>EMP0001</li>\n" +
# "<li>EMP0002</li>\n" +
# "</ol>\n" +
# "</body></html>\n"
Example using an array of XSLT parameters
You can also use an array if you want to.
stylesheet.transform(doc, ["title", "'Employee List'"]).to_xml
# => "<html><body>\n" +
# "<h1>Employee List</h1>\n" +
# "<ol>\n" +
# "<li>EMP0001</li>\n" +
# "<li>EMP0002</li>\n" +
# "</ol>\n" +
# "</body></html>\n"
Or pass an array to XSLT.quote_params:
stylesheet.transform(doc, Nokogiri::XSLT.quote_params(["title", "Aaron's List"])).to_xml
# => "<html><body>\n" +
# "<h1>Aaron's List</h1>\n" +
# "<ol>\n" +
# "<li>EMP0001</li>\n" +
# "<li>EMP0002</li>\n" +
# "</ol>\n" +
# "</body></html>\n"
See: Nokogiri::XSLT.quote_params
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'ext/nokogiri/xslt_stylesheet.c', line 278
static VALUE
rb_xslt_stylesheet_transform(int argc, VALUE *argv, VALUE self)
{
VALUE rb_document, rb_param, rb_error_str;
xmlDocPtr c_document ;
xmlDocPtr c_result_document ;
nokogiriXsltStylesheetTuple *wrapper;
const char **params ;
long param_len ;
int parse_error_occurred ;
int defensive_copy_p = 0;
rb_scan_args(argc, argv, "11", &rb_document, &rb_param);
if (NIL_P(rb_param)) { rb_param = rb_ary_new2(0L) ; }
if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlDocument)) {
rb_raise(rb_eArgError, "argument must be a Nokogiri::XML::Document");
}
/* handle hashes as arguments. */
if (T_HASH == TYPE(rb_param)) {
rb_param = rb_funcall(rb_param, rb_intern("to_a"), 0);
rb_param = rb_funcall(rb_param, rb_intern("flatten"), 0);
}
Check_Type(rb_param, T_ARRAY);
c_document = noko_xml_document_unwrap(rb_document);
TypedData_Get_Struct(self, nokogiriXsltStylesheetTuple, &nokogiri_xslt_stylesheet_tuple_type, wrapper);
param_len = RARRAY_LEN(rb_param);
params = ruby_xcalloc((size_t)param_len + 1, sizeof(char *));
{
// populate params under rb_protect so that a raise from StringValueCStr
// (e.g. on a null byte) does not leak the params allocation.
build_xslt_params_args_t args = { rb_param, param_len, params };
int state = 0;
rb_protect(build_xslt_params, (VALUE)&args, &state);
if (state) {
ruby_xfree(params);
rb_jump_tag(state);
}
}
params[param_len] = 0 ;
xsltTransformContextPtr c_transform_context = xsltNewTransformContext(wrapper->ss, c_document);
if (xsltNeedElemSpaceHandling(c_transform_context) &&
noko_xml_document_has_wrapped_blank_nodes_p(c_document)) {
// see https://github.com/sparklemotion/nokogiri/issues/2800
c_document = xmlCopyDoc(c_document, 1);
defensive_copy_p = 1;
}
xsltFreeTransformContext(c_transform_context);
rb_error_str = rb_str_new(0, 0);
xsltSetGenericErrorFunc((void *)rb_error_str, xslt_generic_error_handler);
xmlSetGenericErrorFunc((void *)rb_error_str, xslt_generic_error_handler);
c_result_document = xsltApplyStylesheet(wrapper->ss, c_document, params);
ruby_xfree(params);
if (defensive_copy_p) {
xmlFreeDoc(c_document);
c_document = NULL;
}
xsltSetGenericErrorFunc(NULL, NULL);
xmlSetGenericErrorFunc(NULL, NULL);
parse_error_occurred = (Qfalse == rb_funcall(rb_error_str, rb_intern("empty?"), 0));
if (parse_error_occurred) {
rb_exc_raise(rb_exc_new3(rb_eRuntimeError, rb_error_str));
}
return noko_xml_document_wrap((VALUE)0, c_result_document) ;
}
|