123456789_123456789_123456789_123456789_123456789_

Class: Nokogiri::XML::Schema

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Inherits: Object
Defined in: lib/nokogiri/xml/schema.rb,
ext/nokogiri/xml_schema.c

Overview

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

Example: Determine whether an ::Nokogiri::XML document is valid.

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

Example: Validate an ::Nokogiri::XML document against a Schema, and capture any errors that are found.

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

⚠ As of 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.

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

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(input) → Nokogiri::XML::Schema) ⇒ Schema .new(input, parse_options) → Nokogiri::XML::Schema) ⇒ Schema

Parse an ::XSD schema definition and create a new Nokogiri::XML:Schema object.

Parameters
  • input (String, IO) ::XSD schema definition

  • #parse_options (Nokogiri::XML::ParseOptions) Defaults to Nokogiri::XML::ParseOptions::DEFAULT_SCHEMA

Returns

Schema

[ GitHub ]

  
# File 'lib/nokogiri/xml/schema.rb', line 70

def self.new(input, parse_options = ParseOptions::DEFAULT_SCHEMA)
  read_memory(input, parse_options)
end

Class Method Details

.from_document(document) → Nokogiri::XML::Schema) .from_document(document, parse_options) → Nokogiri::XML::Schema)

Create a Schema from an already-parsed ::XSD schema definition document.

Parameters
  • document (XML::Document) A document object representing the parsed ::XSD

  • #parse_options (Nokogiri::XML::ParseOptions) Defaults to Nokogiri::XML::ParseOptions::DEFAULT_SCHEMA

Returns

Schema

[ GitHub ]

  
# File 'ext/nokogiri/xml_schema.c', line 169

static VALUE
noko_xml_schema_s_from_document(int argc, VALUE *argv, VALUE rb_class)
{
  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;
}

.read_memory(input) → Nokogiri::XML::Schema) .read_memory(input, parse_options) → Nokogiri::XML::Schema)

Parse an ::XSD schema definition and create a new Schema object.

💡 Note that the limitation of this method relative to .new is that input must be type String, whereas .new also supports IO types.

parameters
  • input (String) ::XSD schema definition

  • #parse_options (Nokogiri::XML::ParseOptions) Defaults to Nokogiri::XML::ParseOptions::DEFAULT_SCHEMA

Returns

Schema

[ GitHub ]

  
# File 'lib/nokogiri/xml/schema.rb', line 89

def self.read_memory(input, parse_options = ParseOptions::DEFAULT_SCHEMA)
  from_document(Nokogiri::XML::Document.parse(input), parse_options)
end

Instance Attribute Details

#errors (rw)

The errors found while parsing the ::XSD

Returns

Array<Nokogiri::XML::SyntaxError>

[ GitHub ]

  
# File 'lib/nokogiri/xml/schema.rb', line 50

attr_accessor :errors

#parse_options (rw)

The options used to parse the schema

Returns

ParseOptions

[ GitHub ]

  
# File 'lib/nokogiri/xml/schema.rb', line 55

attr_accessor :parse_options

Instance Method Details

#valid?(input) → Boolean) ⇒ Boolean

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 Document document

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

Example: Validate an ::Nokogiri::XML document on disk

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

  
# File 'lib/nokogiri/xml/schema.rb', line 147

def valid?(input)
  validate(input).empty?
end

#validate(input) → Array<SyntaxError>)

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 Document document, and capture any errors that are found.

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

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

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

  
# File 'lib/nokogiri/xml/schema.rb', line 115

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

#validate_document(document) (private)

[ GitHub ]

  
# File 'ext/nokogiri/xml_schema.c', line 20

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(rb_filename) (private)

[ GitHub ]

  
# File 'ext/nokogiri/xml_schema.c', line 59

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