class Nokogiri::XSLT::Stylesheet - nokogiri-1.18.10 Documentation

# 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_stylesheet_doc(document) click to toggle source

Parse an `XSLT::Stylesheet` from `document`.

Parameters

- `document` (`Nokogiri::XML::Document`) the document to be parsed.

Returns

  `Nokogiri::XSLT::Stylesheet`

    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_to(document, params = []) → String click to toggle source

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 of `XML::Document` to transform

- `params` is 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.

    # File lib/nokogiri/xslt/stylesheet.rb, line 44
    def apply_to(document, params = [])
      serialize(transform(document, params))
    end

serialize(document) click to toggle source

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(document) click to toggle source
transform(document, params = {})

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`

    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) ;
    }