Class: Nokogiri::XML::Schema

Inherits:
Object
  • Object
show all
Defined in:
lib/nokogiri/xml/schema.rb,
ext/nokogiri/xml_schema.c

Overview

Nokogiri::XML::Schema is used for validating XML against a schema (usually from an xsd file).

Synopsis

Validate an XML document against a Schema. Loop over the errors that are returned and print them out:

xsd = Nokogiri::XML::Schema(File.read(PO_SCHEMA_FILE))
doc = Nokogiri::XML(File.read(PO_XML_FILE))

xsd.validate(doc).each do |error|
  puts error.message
end

The list of errors are Nokogiri::XML::SyntaxError objects.

NOTE: 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://`). Previously, parsing treated documents as “trusted” by default which was counter to Nokogiri’s “untrusted by default” security policy. If a document is trusted, then the caller may turn off the NONET option via the ParseOptions to re-enable external entity resolution over a network connection.

Direct Known Subclasses

RelaxNG

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#errorsObject

Errors while parsing the schema file



38
39
40
# File 'lib/nokogiri/xml/schema.rb', line 38

def errors
  @errors
end

#parse_optionsObject

The Nokogiri::XML::ParseOptions used to parse the schema



40
41
42
# File 'lib/nokogiri/xml/schema.rb', line 40

def parse_options
  @parse_options
end

Class Method Details

.from_document(doc) ⇒ Object

Create a new Schema from the Nokogiri::XML::Document doc



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'ext/nokogiri/xml_schema.c', line 197

static VALUE
from_document(int argc, VALUE *argv, VALUE klass)
{
  VALUE document;
  VALUE parse_options;
  int parse_options_int;
  xmlDocPtr doc;
  xmlSchemaParserCtxtPtr ctx;
  xmlSchemaPtr schema;
  VALUE errors;
  VALUE rb_schema;
  int scanned_args = 0;
  xmlExternalEntityLoader old_loader = 0;

  scanned_args = rb_scan_args(argc, argv, "11", &document, &parse_options);

  Data_Get_Struct(document, xmlDoc, doc);
  doc = doc->doc; /* In case someone passes us a node. ugh. */

  if (scanned_args == 1) {
    parse_options = rb_const_get_at(rb_const_get_at(mNokogiriXml, rb_intern("ParseOptions")), rb_intern("DEFAULT_SCHEMA"));
  }
  parse_options_int = (int)NUM2INT(rb_funcall(parse_options, rb_intern("to_i"), 0));

  if (has_blank_nodes_p(DOC_NODE_CACHE(doc))) {
    rb_raise(rb_eArgError, "Creating a schema from a document that has blank nodes exposed to Ruby is dangerous");
  }

  ctx = xmlSchemaNewDocParserCtxt(doc);

  errors = rb_ary_new();
  xmlSetStructuredErrorFunc((void *)errors, Nokogiri_error_array_pusher);

#ifdef HAVE_XMLSCHEMASETPARSERSTRUCTUREDERRORS
  xmlSchemaSetParserStructuredErrors(
    ctx,
    Nokogiri_error_array_pusher,
    (void *)errors
  );
#endif

  if (parse_options_int & XML_PARSE_NONET) {
    old_loader = xmlGetExternalEntityLoader();
    xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader);
  }

  schema = xmlSchemaParse(ctx);

  if (old_loader) {
    xmlSetExternalEntityLoader(old_loader);
  }

  xmlSetStructuredErrorFunc(NULL, NULL);
  xmlSchemaFreeParserCtxt(ctx);

  if (NULL == schema) {
    xmlErrorPtr error = xmlGetLastError();
    if (error) {
      Nokogiri_error_raise(NULL, error);
    } else {
      rb_raise(rb_eRuntimeError, "Could not parse document");
    }

    return Qnil;
  }

  rb_schema = Data_Wrap_Struct(klass, 0, dealloc, schema);
  rb_iv_set(rb_schema, "@errors", errors);
  rb_iv_set(rb_schema, "@parse_options", parse_options);

  return rb_schema;

  return Qnil;
}

.new(string_or_io, options = ParseOptions::DEFAULT_SCHEMA) ⇒ Object

Create a new Nokogiri::XML::Schema object using a string_or_io object.



45
46
47
# File 'lib/nokogiri/xml/schema.rb', line 45

def self.new string_or_io, options = ParseOptions::DEFAULT_SCHEMA
  from_document(Nokogiri::XML(string_or_io), options)
end

.read_memory(string) ⇒ Object

Create a new Schema from the contents of string



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'ext/nokogiri/xml_schema.c', line 101

static VALUE
read_memory(int argc, VALUE *argv, VALUE klass)
{
  VALUE content;
  VALUE parse_options;
  int parse_options_int;
  xmlSchemaParserCtxtPtr ctx;
  xmlSchemaPtr schema;
  VALUE errors;
  VALUE rb_schema;
  int scanned_args = 0;
  xmlExternalEntityLoader old_loader = 0;

  scanned_args = rb_scan_args(argc, argv, "11", &content, &parse_options);
  if (scanned_args == 1) {
    parse_options = rb_const_get_at(rb_const_get_at(mNokogiriXml, rb_intern("ParseOptions")), rb_intern("DEFAULT_SCHEMA"));
  }
  parse_options_int = (int)NUM2INT(rb_funcall(parse_options, rb_intern("to_i"), 0));

  ctx = xmlSchemaNewMemParserCtxt((const char *)StringValuePtr(content), (int)RSTRING_LEN(content));

  errors = rb_ary_new();
  xmlSetStructuredErrorFunc((void *)errors, Nokogiri_error_array_pusher);

#ifdef HAVE_XMLSCHEMASETPARSERSTRUCTUREDERRORS
  xmlSchemaSetParserStructuredErrors(
    ctx,
    Nokogiri_error_array_pusher,
    (void *)errors
  );
#endif

  if (parse_options_int & XML_PARSE_NONET) {
    old_loader = xmlGetExternalEntityLoader();
    xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader);
  }

  schema = xmlSchemaParse(ctx);

  if (old_loader) {
    xmlSetExternalEntityLoader(old_loader);
  }

  xmlSetStructuredErrorFunc(NULL, NULL);
  xmlSchemaFreeParserCtxt(ctx);

  if (NULL == schema) {
    xmlErrorPtr error = xmlGetLastError();
    if (error) {
      Nokogiri_error_raise(NULL, error);
    } else {
      rb_raise(rb_eRuntimeError, "Could not parse document");
    }

    return Qnil;
  }

  rb_schema = Data_Wrap_Struct(klass, 0, dealloc, schema);
  rb_iv_set(rb_schema, "@errors", errors);
  rb_iv_set(rb_schema, "@parse_options", parse_options);

  return rb_schema;
}

Instance Method Details

#valid?(thing) ⇒ Boolean

Returns true if thing is a valid Nokogiri::XML::Document or file.

Returns:

  • (Boolean)


67
68
69
# File 'lib/nokogiri/xml/schema.rb', line 67

def valid? thing
  validate(thing).length == 0
end

#validate(thing) ⇒ Object

Validate thing against this schema. thing can be a Nokogiri::XML::Document object, or a filename. An Array of Nokogiri::XML::SyntaxError objects found while validating the thing is returned.



54
55
56
57
58
59
60
61
62
# File 'lib/nokogiri/xml/schema.rb', line 54

def validate thing
  if thing.is_a?(Nokogiri::XML::Document) 
    validate_document(thing) 
  elsif File.file?(thing)
    validate_file(thing)
  else
    raise ArgumentError, "Must provide Nokogiri::Xml::Document or the name of an existing file"
  end
end