class Nokogiri::XSLT::Stylesheet
A Stylesheet
represents an XSLT
Stylesheet
object. Stylesheet
creation is done through 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
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.
Public Class Methods
Parse an XSLT::Stylesheet
from document
.
- Parameters
-
document
(Nokogiri::XML::Document
) the document to be parsed.
- Returns
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); }
Public Instance Methods
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
-
document
is an instance ofXML::Document
to transform -
params
is an array of strings used asXSLT
parameters, passed into#transform
- Returns
-
A string containing the serialized result of the transformation.
See Nokogiri::XSLT::Stylesheet#transform
for more information and examples.
# File lib/nokogiri/xslt/stylesheet.rb, line 44 def apply_to(document, params = []) serialize(transform(document, params)) end
Serialize document
to an xml string, as specified by the method
parameter in the Stylesheet
.
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 an XML::Document
as defined by an XSLT::Stylesheet
.
- Parameters
-
document
(Nokogiri::XML::Document
) the document to be transformed. -
params
(Hash, Array) strings used asXSLT
parameters.
- Returns
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
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, j ; 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 *)); for (j = 0 ; j < param_len ; j++) { VALUE entry = rb_ary_entry(rb_param, j); const char *ptr = StringValueCStr(entry); params[j] = ptr; } 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) ; }