class Nokogiri::XML::Schema - nokogiri-1.18.10 Documentation

# class Nokogiri::XML::Schema

`Nokogiri::XML::Schema` is used for validating XML against an XSD schema definition.

⚠ Since v1.11.0, `Schema` treats inputs as untrusted by default, and so external entities are not resolved from the network (`http://` or `ftp://`). When parsing a trusted document, the caller may turn off the `NONET` option via the `ParseOptions` to (re-)enable external entity resolution over a network connection.

🛡 Before v1.11.0, documents were “trusted” by default during schema parsing which was counter to Nokogiri’s “untrusted by default” security policy.

Example: Determine whether an XML document is valid.

    schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
    doc = Nokogiri::XML::Document.parse(File.read(XML_FILE))
    schema.valid?(doc) # Boolean

Example: Validate an XML document against an XSD schema, and capture any errors that are found.

    schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
    doc = Nokogiri::XML::Document.parse(File.read(XML_FILE))
    errors = schema.validate(doc) # Array<SyntaxError>

Example: Validate an XML document using a `Document` containing an XSD schema definition.

    schema_doc = Nokogiri::XML::Document.parse(File.read(RELAX_NG_FILE))
    schema = Nokogiri::XML::Schema.from_document(schema_doc)
    doc = Nokogiri::XML::Document.parse(File.read(XML_FILE))
    schema.valid?(doc) # Boolean

### Attributes

errors[RW]

The errors found while parsing the XSD

Returns

  Array<Nokogiri::XML::SyntaxError>

parse_options[RW]

The options used to parse the schema

Returns

  `Nokogiri::XML::ParseOptions`

### Public Class Methods

from_document(input) → Nokogiri::XML::Schema click to toggle source
from_document(input, parse_options) → Nokogiri::XML::Schema

Parse an XSD schema definition from a `Document` to create a new `Nokogiri::XML::Schema`

Parameters

- `input` (`XML::Document`) A document containing the XSD schema definition

- `parse_options` (`Nokogiri::XML::ParseOptions`) Defaults to Nokogiri::XML::ParseOptions::DEFAULT_SCHEMA

Returns

  `Nokogiri::XML::Schema`

    static VALUE
    noko_xml_schema_s_from_document(int argc, VALUE *argv, VALUE rb_class)
    {
      /* TODO: deprecate this method and put file-or-string logic into .new so that becomes the
       * preferred entry point, and this can become a private method */
      VALUE rb_document;
      VALUE rb_parse_options;
      VALUE rb_schema;
      xmlDocPtr c_document;
      xmlSchemaParserCtxtPtr c_parser_context;
      int defensive_copy_p = 0;

      rb_scan_args(argc, argv, "11", &rb_document, &rb_parse_options);

      if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlNode)) {
        rb_raise(rb_eTypeError,
                 "expected parameter to be a Nokogiri::XML::Document, received %"PRIsVALUE,
                 rb_obj_class(rb_document));
      }

      if (!rb_obj_is_kind_of(rb_document, cNokogiriXmlDocument)) {
        xmlNodePtr deprecated_node_type_arg;
        NOKO_WARN_DEPRECATION("Passing a Node as the first parameter to Schema.from_document is deprecated. Please pass a Document instead. This will become an error in Nokogiri v1.17.0."); // TODO: deprecated in v1.15.3, remove in v1.17.0
        Noko_Node_Get_Struct(rb_document, xmlNode, deprecated_node_type_arg);
        c_document = deprecated_node_type_arg->doc;
      } else {
        c_document = noko_xml_document_unwrap(rb_document);
      }

      if (noko_xml_document_has_wrapped_blank_nodes_p(c_document)) {
        // see https://github.com/sparklemotion/nokogiri/pull/2001
        c_document = xmlCopyDoc(c_document, 1);
        defensive_copy_p = 1;
      }

      c_parser_context = xmlSchemaNewDocParserCtxt(c_document);
      rb_schema = xml_schema_parse_schema(rb_class, c_parser_context, rb_parse_options);

      if (defensive_copy_p) {
        xmlFreeDoc(c_document);
        c_document = NULL;
      }

      return rb_schema;
    }

new(input) → Nokogiri::XML::Schema click to toggle source
new(input, parse_options) → Nokogiri::XML::Schema

Parse an XSD schema definition from a String or IO to create a new `Nokogiri::XML::Schema`

Parameters

- `input` (String | IO) XSD schema definition

- `parse_options` (`Nokogiri::XML::ParseOptions`) Defaults to Nokogiri::XML::ParseOptions::DEFAULT_SCHEMA

Returns

  `Nokogiri::XML::Schema`

    # File lib/nokogiri/xml/schema.rb, line 69
    def self.new(input, parse_options_ = ParseOptions::DEFAULT_SCHEMA, parse_options: parse_options_)
      from_document(Nokogiri::XML::Document.parse(input), parse_options)
    end

read_memory(input) → Nokogiri::XML::Schema click to toggle source
read_memory(input, parse_options) → Nokogiri::XML::Schema

Convenience method for `Nokogiri::XML::Schema.new`

    # File lib/nokogiri/xml/schema.rb, line 78
    def self.read_memory(...)
      # TODO deprecate this method
      new(...)
    end

### Public Instance Methods

valid?(input) → Boolean click to toggle source

Validate `input` and return a Boolean indicating whether the document is valid

Parameters

- `input` (`Nokogiri::XML::Document` | String) A parsed document, or a string containing a local filename.

Returns

  Boolean

Example: Validate an existing `XML::Document`

    schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
    return unless schema.valid?(document)

Example: Validate an XML document on disk

    schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
    return unless schema.valid?("/path/to/file.xml")

    # File lib/nokogiri/xml/schema.rb, line 135
    def valid?(input)
      validate(input).empty?
    end

validate(input) → Array<SyntaxError> click to toggle source

Validate `input` and return any errors that are found.

Parameters

- `input` (`Nokogiri::XML::Document` | String) A parsed document, or a string containing a local filename.

Returns

  Array<SyntaxError>

Example: Validate an existing `XML::Document`, and capture any errors that are found.

    schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
    errors = schema.validate(document)

Example: Validate an XML document on disk, and capture any errors that are found.

    schema = Nokogiri::XML::Schema.new(File.read(XSD_FILE))
    errors = schema.validate("/path/to/file.xml")

    # File lib/nokogiri/xml/schema.rb, line 104
    def validate(input)
      if input.is_a?(Nokogiri::XML::Document)
        validate_document(input)
      elsif File.file?(input)
        validate_file(input)
      else
        raise ArgumentError, "Must provide Nokogiri::XML::Document or the name of an existing file"
      end
    end

### Private Instance Methods

validate_document(p1) click to toggle source

    static VALUE
    noko_xml_schema__validate_document(VALUE self, VALUE document)
    {
      xmlDocPtr doc;
      xmlSchemaPtr schema;
      xmlSchemaValidCtxtPtr valid_ctxt;
      VALUE errors;

      TypedData_Get_Struct(self, xmlSchema, &xml_schema_type, schema);
      doc = noko_xml_document_unwrap(document);

      errors = rb_ary_new();

      valid_ctxt = xmlSchemaNewValidCtxt(schema);

      if (NULL == valid_ctxt) {
        /* we have a problem */
        rb_raise(rb_eRuntimeError, "Could not create a validation context");
      }

      xmlSchemaSetValidStructuredErrors(
        valid_ctxt,
        noko__error_array_pusher,
        (void *)errors
      );

      int status = xmlSchemaValidateDoc(valid_ctxt, doc);

      xmlSchemaFreeValidCtxt(valid_ctxt);

      if (status != 0) {
        if (RARRAY_LEN(errors) == 0) {
          rb_ary_push(errors, rb_str_new2("Could not validate document"));
        }
      }

      return errors;
    }

validate_file(p1) click to toggle source

    static VALUE
    noko_xml_schema__validate_file(VALUE self, VALUE rb_filename)
    {
      xmlSchemaPtr schema;
      xmlSchemaValidCtxtPtr valid_ctxt;
      const char *filename ;
      VALUE errors;

      TypedData_Get_Struct(self, xmlSchema, &xml_schema_type, schema);
      filename = (const char *)StringValueCStr(rb_filename) ;

      errors = rb_ary_new();

      valid_ctxt = xmlSchemaNewValidCtxt(schema);

      if (NULL == valid_ctxt) {
        /* we have a problem */
        rb_raise(rb_eRuntimeError, "Could not create a validation context");
      }

      xmlSchemaSetValidStructuredErrors(
        valid_ctxt,
        noko__error_array_pusher,
        (void *)errors
      );

      int status = xmlSchemaValidateFile(valid_ctxt, filename, 0);

      xmlSchemaFreeValidCtxt(valid_ctxt);

      if (status != 0) {
        if (RARRAY_LEN(errors) == 0) {
          rb_ary_push(errors, rb_str_new2("Could not validate file."));
        }
      }

      return errors;
    }