libxml-ruby-5.0.3/0000755000004100000410000000000014620142101014004 5ustar www-datawww-datalibxml-ruby-5.0.3/libxml-ruby.gemspec0000644000004100000410000000367214620142101017627 0ustar www-datawww-data# encoding: utf-8 require 'date' # Determine the current version of the software version = File.read('ext/libxml/ruby_xml_version.h').match(/\s*RUBY_LIBXML_VERSION\s*['"](\d.+)['"]/)[1] Gem::Specification.new do |spec| spec.name = 'libxml-ruby' spec.version = version spec.homepage = 'https://xml4r.github.io/libxml-ruby/' spec.summary = 'Ruby Bindings for LibXML2' spec.description = <<-EOS The Libxml-Ruby project provides Ruby language bindings for the GNOME Libxml2 XML toolkit. It is free software, released under the MIT License. Libxml-ruby's primary advantage over REXML is performance - if speed is your need, these are good libraries to consider, as demonstrated by the informal benchmark below. EOS spec.authors = ['Ross Bamform', 'Wai-Sun Chia', 'Sean Chittenden', 'Dan Janwoski', 'Anurag Priyam', 'Charlie Savage', 'Ryan Johnson'] spec.platform = Gem::Platform::RUBY spec.bindir = 'bin' spec.extensions = ['ext/libxml/extconf.rb'] spec.files = Dir.glob(['HISTORY', 'LICENSE', 'libxml-ruby.gemspec', 'MANIFEST', 'Rakefile', 'README.rdoc', 'setup.rb', 'ext/libxml/*.def', 'ext/libxml/*.h', 'ext/libxml/*.c', 'ext/libxml/*.rb', 'ext/vc/*.sln', 'ext/vc/*.vcprojx', 'lib/**/*.rb', 'script/**/*', 'test/**/*']) spec.test_files = Dir.glob('test/test_*.rb') spec.required_ruby_version = '>= 2.5' spec.date = DateTime.now spec.add_development_dependency('rake-compiler') spec.add_development_dependency('minitest') spec.license = 'MIT' end libxml-ruby-5.0.3/README.rdoc0000644000004100000410000002062014620142101015612 0ustar www-datawww-data= LibXML Ruby == Overview The libxml gem provides Ruby language bindings for GNOME's Libxml2 XML toolkit. It is free software, released under the MIT License. We think libxml-ruby is the best XML library for Ruby because: * Speed - Its much faster than REXML and Hpricot * Features - It provides an amazing number of featues * Conformance - It passes all 1800+ tests from the OASIS XML Tests Suite == Requirements libxml-ruby requires Ruby 3.0.0 or higher. It depends on libxml2 to function properly. libxml2, in turn, depends on: * libm (math routines: very standard) * libz (zlib) * libiconv If you are running Linux or Unix you'll need a C compiler so the extension can be compiled when it is installed. If you are running Windows, then install the x64-mingw-ucr gem or build it yourself using (Ruby for Windows)[https://rubyinstaller.org/] or directly with msys2[https://msys2.github.io/] and ucrt64. == Installation The easiest way to install libxml-ruby is via RubyGems. To install: gem install libxml-ruby If the extension compile process cannot find libxml2, you may need to indicate the location of the libxml2 configuration utility as it is used to find the required header and include files. (If you need to indicate a location for the libxml2 library or header files different than reported by xml2-config, see the additional configuration options.) This may be done with RubyGems: gem install libxml-ruby -- --with-xml2-dir=/path/to/xml2-config Or bundler: bundle config build.libxml-ruby --with-xml2-config=/path/to/xml2-config bundle install libxml-ruby If you are running Windows, then install the libxml-ruby-x64-mingw32 gem. The gem includes prebuilt extensions for Ruby 3.2 and 3.3. The gem also includes a Microsoft VC++ solution and XCode project - these are very useful for debugging. libxml-ruby's source codes lives on GitHub[https://github.com/xml4r/libxml-ruby]. == Getting Started Using libxml is easy. First decide what parser you want to use: * Generally you'll want to use the LibXML::XML::Parser which provides a tree based API. * For larger documents that don't fit into memory, or if you prefer an input based API, use the LibXML::XML::Reader. * To parse HTML files use LibXML::XML::HTMLParser. * If you are masochistic, then use the LibXML::XML::SaxParser, which provides a callback API. Once you have chosen a parser, choose a datasource. Libxml can parse files, strings, URIs and IO streams. For each data source you can specify an LibXML::XML::Encoding, a base uri and various parser options. For more information, refer the LibXML::XML::Parser.document, LibXML::XML::Parser.file, LibXML::XML::Parser.io or LibXML:::XML::Parser.string methods (the same methods are defined on all four parser classes). == Advanced Functionality Beyond the basics of parsing and processing XML and HTML documents, libxml provides a wealth of additional functionality. Most commonly, you'll want to use its LibXML::XML::XPath support, which makes it easy to find data inside an XML document. Although not as popular, LibXML::XML::XPointer provides another API for finding data inside an XML document. Often times you'll need to validate data before processing it. For example, if you accept user generated content submitted over the Web, you'll want to verify that it does not contain malicious code such as embedded scripts. This can be done using libxml's powerful set of validators: * DTDs (LibXML::XML::Dtd) * Relax Schemas (LibXML::XML::RelaxNG) * XML Schema (LibXML::XML::Schema) Finally, if you'd like to use XSL Transformations to process data, then install the {libxslt gem}[https://github.com/xml4r/libxslt-rubygem]. == Usage For information about using libxml-ruby please refer to its documentation[http://xml4r.github.io/libxml-ruby]. Some tutorials are also available[https://github.com/xml4r/libxml-ruby/wiki]. All libxml classes are in the LibXML::XML module. The easiest way to use libxml is to require 'xml'. This will mixin the LibXML module into the global namespace, allowing you to write code like this: require 'xml' document = XML::Document.new However, when creating an application or library you plan to redistribute, it is best to not add the LibXML module to the global namespace, in which case you can either write your code like this: require 'libxml' document = LibXML::XML::Document.new Or you can utilize a namespace for your own work and include LibXML into it. For example: require 'libxml' module MyApplication include LibXML class MyClass def some_method document = XML::Document.new end end end For simplicity's sake, the documentation uses the xml module in its examples. == Tests To run tests you first need to build the shared libary: rake compile Once you have build the shared libary, you can then run tests using rake: rake test +Build status: {rdoc-image:https://github.com/xml4r/libxml-ruby/actions/workflows/mri.yml/badge.svg}[https://github.com/xml4r/libxml-ruby/actions/workflows/mri.yml] == Performance In addition to being feature rich and conformation, the main reason people use libxml-ruby is for performance. Here are the results of a couple simple benchmarks recently blogged about on the Web (you can find them in the benchmark directory of the libxml distribution). From http://depixelate.com/2008/4/23/ruby-xml-parsing-benchmarks user system total real libxml 0.032000 0.000000 0.032000 ( 0.031000) Hpricot 0.640000 0.031000 0.671000 ( 0.890000) REXML 1.813000 0.047000 1.860000 ( 2.031000) From https://svn.concord.org/svn/projects/trunk/common/ruby/xml_benchmarks/ user system total real libxml 0.641000 0.031000 0.672000 ( 0.672000) hpricot 5.359000 0.062000 5.421000 ( 5.516000) rexml 22.859000 0.047000 22.906000 ( 23.203000) == Documentation Documentation is available via rdoc, and is installed automatically with the gem. libxml-ruby's {online documentation}[https://xml4r.github.io/libxml-ruby/rdoc/index.html] is generated using Hanna, which is a development gem dependency. Note that older versions of Rdoc, which ship with Ruby 1.8.x, will report a number of errors. To avoid them, install Rdoc 2.1 or higher. Once you have installed the gem, you'll have to disable the version of Rdoc that Ruby 1.8.x includes. An easy way to do that is rename the directory ruby/lib/ruby/1.8/rdoc to ruby/lib/ruby/1.8/rdoc_old. == Support If you have any questions about using libxml-ruby, please report an issue on GitHub[https://github.com/xml4r/libxml-ruby/issues]. == Memory Management libxml-ruby automatically manages memory associated with the underlying libxml2 library. The bindings create a one-to-one mapping between Ruby objects and libxml documents and libxml parent nodes (ie, nodes that do not have a parent and do not belong to a document). In these cases, the bindings manage the memory. They do this by installing a free function and storing a back pointer to the Ruby object from the xmlnode using the _private member on libxml structures. When the Ruby object goes out of scope, the underlying libxml structure is freed. Libxml itself then frees all child nodes (recursively). For all other nodes (the vast majority), the bindings create temporary Ruby objects that get freed once they go out of scope. Thus there can be more than one Ruby object pointing to the same xml node. To mostly hide this from a programmer on the Ruby side, the #eql? and #== methods are overriden to check if two Ruby objects wrap the same xmlnode. If they do, then the methods return true. During the mark phase, each of these temporary objects marks its owning document, thereby keeping the Ruby document object alive and thus the xmldoc tree. In the sweep phase of the garbage collector, or when a program ends, there is no order to how Ruby objects are freed. In fact, the Ruby document object is almost always freed before any Ruby objects that wrap child nodes. However, this is ok because those Ruby objects do not have a free function and are no longer in scope (since if they were the document would not be freed). == License See LICENSE for license information. libxml-ruby-5.0.3/lib/0000755000004100000410000000000014620142101014552 5ustar www-datawww-datalibxml-ruby-5.0.3/lib/libxml/0000755000004100000410000000000014620142101016041 5ustar www-datawww-datalibxml-ruby-5.0.3/lib/libxml/sax_callbacks.rb0000644000004100000410000001241514620142101021163 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class SaxParser module Callbacks # Called for a CDATA block event. def on_cdata_block(cdata) end # Called for a characters event. def on_characters(chars) end # Called for a comment event. def on_comment(msg) end # Called for a end document event. def on_end_document end # Called for a end element event. def on_end_element_ns(name, prefix, uri) end # Called for parser errors. def on_error(msg) end # Called for an external subset event. def on_external_subset(name, external_id, system_id) end # Called for an external subset notification event. def on_has_external_subset end # Called for an internal subset notification event. def on_has_internal_subset end # Called for an internal subset event. def on_internal_subset(name, external_id, system_id) end # Called for 'is standalone' event. def on_is_standalone end # Called for an processing instruction event. def on_processing_instruction(target, data) end # Called for a reference event. def on_reference(name) end # Called for a start document event. def on_start_document end # Called for a start element event. def on_start_element_ns(name, attributes, prefix, uri, namespaces) end end module VerboseCallbacks # Called for a CDATA block event. def on_cdata_block(cdata) STDOUT << "on_cdata_block" << "\n" << " cdata " << cdata << "\n" STDOUT.flush end # Called for a characters event. def on_characters(chars) STDOUT << "on_characters" << "\n" << " chars " << chars << "\n" STDOUT.flush end # Called for a comment event. def on_comment(comment) STDOUT << "on_comment" << "\n" << " comment: " << comment << "\n" STDOUT.flush end # Called for a end document event. def on_end_document STDOUT << "on_end_document\n" STDOUT.flush end # Called for a end element event. def on_end_element_ns(name, prefix, uri) STDOUT << "on_end_element_ns" << "\n" << " name: " << name << "\n" << " prefix: " << prefix << "\n" << " uri: " << uri << "\n" STDOUT.flush end # Called for parser errors. def on_error(error) STDOUT << "on_error" << "\n" " error " << error << "\n" STDOUT.flush end # Called for an external subset event. def on_external_subset(name, external_id, system_id) STDOUT << "on_external_subset" << "\n" " external_id " << external_id << "\n" << " system_id " << system_id << "\n" STDOUT.flush end # Called for an external subset notification event. def on_has_external_subset STDOUT << "on_has_internal_subset\n" STDOUT.flush end # Called for an internal subset notification event. def on_has_internal_subset STDOUT << "on_has_internal_subset\n" STDOUT.flush end # Called for an internal subset event. def on_internal_subset(name, external_id, system_id) STDOUT << "on_internal_subset" << "\n" " external_id " << external_id << "\n" << " system_id " << system_id << "\n" STDOUT.flush end # Called for 'is standalone' event. def on_is_standalone STDOUT << "on_is_standalone\n" STDOUT.flush end # Called for an processing instruction event. def on_processing_instruction(target, data) STDOUT << "on_characters" << "\n" " target: " << target << "\n" << " data: " << data << "\n" STDOUT.flush end # Called for a reference event. def on_reference(name) STDOUT << "on_reference:" << "\n" << " name:" << name << "\n" STDOUT.flush end # Called for a start document event. def on_start_document STDOUT << "on_start_document\n" STDOUT.flush end # Called for a start element event. def on_start_element_ns(name, attributes, prefix, uri, namespaces) STDOUT << "on_start_element_ns" << "\n" << " name: " << name << "\n" << " attr: " << (attributes || Hash.new).inspect << "\n" << " prefix: " << prefix << "\n" << " uri: " << uri << "\n" << " ns_defs: " << (namespaces || Hash.new).inspect << "\n" STDOUT.flush end end end end endlibxml-ruby-5.0.3/lib/libxml/attr_decl.rb0000644000004100000410000000361714620142101020336 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class AttrDecl include Enumerable # call-seq: # attr_decl.child -> nil # # Obtain this attribute declaration's child attribute(s). # It will always be nil. def child nil end # call-seq: # attr_decl.child? -> (true|false) # # Returns whether this attribute declaration has child attributes. # def child? not self.children.nil? end # call-seq: # attr_decl.doc? -> (true|false) # # Determine whether this attribute declaration is associated with an # XML::Document. def doc? not self.doc.nil? end # call-seq: # attr_decl.next? -> (true|false) # # Determine whether there is a next attribute declaration. def next? not self.next.nil? end # call-seq: # attr_decl.parent? -> (true|false) # # Determine whether this attribute declaration has a parent . def parent? not self.parent.nil? end # call-seq: # attr_decl.prev? -> (true|false) # # Determine whether there is a previous attribute declaration. def prev? not self.prev.nil? end # call-seq: # attr_decl.node_type_name -> 'attribute declaration' # # Returns this attribute declaration's node type name. def node_type_name if node_type == Node::ATTRIBUTE_DECL 'attribute declaration' else raise(UnknownType, "Unknown node type: %n", node.node_type); end end # call-seq: # attr_decl.to_s -> string # # Returns a string representation of this attribute declaration. def to_s "#{name} = #{value}" end end end end libxml-ruby-5.0.3/lib/libxml/error.rb0000644000004100000410000000512714620142101017524 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Error # Create mapping from domain constant values to keys DOMAIN_CODE_MAP = [:NO_ERROR, :PARSER, :TREE, :NAMESPACE, :DTD, :HTML, :MEMORY, :OUTPUT, :IO, :FTP, :HTTP, :XINCLUDE, :XPATH, :XPOINTER, :REGEXP, :DATATYPE, :SCHEMASP, :SCHEMASV, :RELAXNGP, :RELAXNGV, :CATALOG, :C14N, :XSLT, :VALID, :CHECK, :WRITER, :MODULE, :I18N, :SCHEMATRONV].inject(Hash.new) do |hash, code| if const_defined?(code) hash[const_get(code)] = code end hash end # Create mapping from error constant values (so need to remove domain_codes) to keys ERROR_CODE_MAP = Hash.new.tap do |map| (constants - DOMAIN_CODE_MAP.values - #Domains [:NONE, :WARNING, :ERROR, :FATAL] # Levels ).each do |code| map[const_get(code)] = code end end # Verbose error handler VERBOSE_HANDLER = lambda do |error| STDERR << error.to_s << "\n" STDERR.flush end # Quiet error handler QUIET_HANDLER = lambda do |error| end def ==(other) eql?(other) end def eql?(other) self.code == other.code and self.domain == other.domain and self.message == other.message and self.level == other.level and self.file == other.file and self.line == other.line and self.str1 == other.str1 and self.str2 == other.str2 and self.str3 == other.str3 and self.int1 == other.int1 and self.int2 == other.int2 and self.ctxt == other.ctxt and self.node == other.node rescue false end def level_to_s case self.level when NONE '' when WARNING 'Warning:' when ERROR 'Error:' when FATAL 'Fatal error:' end end def domain_to_s DOMAIN_CODE_MAP[self.domain].to_s end def code_to_s ERROR_CODE_MAP[self.code].to_s end def to_s msg = super msg = msg ? msg.strip: '' if self.line sprintf("%s %s at %s:%d.", self.level_to_s, msg, self.file, self.line) else sprintf("%s %s.", self.level_to_s, msg) end end end end end LibXML::XML::Error.set_handler(&LibXML::XML::Error::VERBOSE_HANDLER) libxml-ruby-5.0.3/lib/libxml/schema.rb0000644000004100000410000000374214620142101017634 0ustar www-datawww-datamodule LibXML module XML class Schema module Types XML_SCHEMA_TYPE_BASIC = 1 # A built-in datatype XML_SCHEMA_TYPE_ANY = 2 XML_SCHEMA_TYPE_FACET = 3 XML_SCHEMA_TYPE_SIMPLE = 4 XML_SCHEMA_TYPE_COMPLEX = 5 XML_SCHEMA_TYPE_SEQUENCE = 6 XML_SCHEMA_TYPE_CHOICE = 7 XML_SCHEMA_TYPE_ALL = 8 XML_SCHEMA_TYPE_SIMPLE_CONTENT = 9 XML_SCHEMA_TYPE_COMPLEX_CONTENT = 10 XML_SCHEMA_TYPE_UR = 11 XML_SCHEMA_TYPE_RESTRICTION = 12 XML_SCHEMA_TYPE_EXTENSION = 13 XML_SCHEMA_TYPE_ELEMENT = 14 XML_SCHEMA_TYPE_ATTRIBUTE = 15 XML_SCHEMA_TYPE_ATTRIBUTEGROUP = 16 XML_SCHEMA_TYPE_GROUP = 17 XML_SCHEMA_TYPE_NOTATION = 18 XML_SCHEMA_TYPE_LIST = 19 XML_SCHEMA_TYPE_UNION = 20 XML_SCHEMA_TYPE_ANY_ATTRIBUTE = 21 XML_SCHEMA_TYPE_IDC_UNIQUE = 22 XML_SCHEMA_TYPE_IDC_KEY = 23 XML_SCHEMA_TYPE_IDC_KEYREF = 24 XML_SCHEMA_TYPE_PARTICLE = 25 XML_SCHEMA_TYPE_ATTRIBUTE_USE = 26 XML_SCHEMA_FACET_MININCLUSIVE = 1000 XML_SCHEMA_FACET_MINEXCLUSIVE = 1001 XML_SCHEMA_FACET_MAXINCLUSIVE = 1002 XML_SCHEMA_FACET_MAXEXCLUSIVE = 1003 XML_SCHEMA_FACET_TOTALDIGITS = 1004 XML_SCHEMA_FACET_FRACTIONDIGITS = 1005 XML_SCHEMA_FACET_PATTERN = 1006 XML_SCHEMA_FACET_ENUMERATION = 1007 XML_SCHEMA_FACET_WHITESPACE = 1008 XML_SCHEMA_FACET_LENGTH = 1009 XML_SCHEMA_FACET_MAXLENGTH = 1010 XML_SCHEMA_FACET_MINLENGTH = 1011 XML_SCHEMA_EXTRA_QNAMEREF = 2000 XML_SCHEMA_EXTRA_ATTR_USE_PROHIB = 2001 end end end endlibxml-ruby-5.0.3/lib/libxml/node.rb0000644000004100000410000002070614620142101017320 0ustar www-datawww-data# encoding: UTF-8 require 'stringio' module LibXML module XML class Node # Determines whether this node has attributes def attributes? attributes.length > 0 end # Create a shallow copy of the node. To create # a deep copy call Node#copy(true) def clone copy(false) end # call-seq: # node.inner_xml -> "string" # node.inner_xml(:indent => true, :encoding => 'UTF-8', :level => 0) -> "string" # # Converts a node's children to a string representation. To include # the node, use XML::Node#to_s. For more information about # the supported options, see XML::Node#to_s. def inner_xml(options = Hash.new) io = nil self.each do |node| xml = node.to_s(options) # Create the string IO here since we now know the encoding io = create_string_io(xml) unless io io << xml end io ? io.string : nil end # :call-seq: # node.dup -> XML::Node # # Create a shallow copy of the node. To create # a deep copy call Node#copy(true) def dup copy(false) end # call-seq: # node.context(namespaces=nil) -> XPath::Context # # Returns a new XML::XPathContext for the current node. # # Namespaces is an optional array of XML::NS objects def context(nslist = nil) if not self.doc raise(TypeError, "A node must belong to a document before a xpath context can be created") end context = XPath::Context.new(self.doc) context.node = self context.register_namespaces_from_node(self) context.register_namespaces_from_node(self.doc.root) context.register_namespaces(nslist) if nslist context end # call-seq: # node.find(namespaces=nil) -> XPath::XPathObject # # Return nodes matching the specified xpath expression. # For more information, please refer to the documentation # for XML::Document#find. # # Namespaces is an optional array of XML::NS objects def find(xpath, nslist = nil) self.context(nslist).find(xpath) end # call-seq: # node.find_first(namespaces=nil) -> XML::Node # # Return the first node matching the specified xpath expression. # For more information, please refer to the documentation # for the #find method. def find_first(xpath, nslist = nil) find(xpath, nslist).first end # call-seq: # node.namespacess -> XML::Namespaces # # Returns this node's XML::Namespaces object, # which is used to access the namespaces # associated with this node. def namespaces @namespaces ||= XML::Namespaces.new(self) end # ------- Traversal ---------------- # Iterates over this node's attributes. # # doc = XML::Document.new('model/books.xml') # doc.root.each_attr {|attr| puts attr} def each_attr attributes.each do |attr| yield(attr) end end # Iterates over this node's child elements (nodes # that have a node_type == ELEMENT_NODE). # # doc = XML::Document.new('model/books.xml') # doc.root.each_element {|element| puts element} def each_element each do |node| yield(node) if node.node_type == ELEMENT_NODE end end # Determines whether this node has a parent node def parent? not parent.nil? end # Determines whether this node has a first node def first? not first.nil? end # Returns this node's children as an array. def children entries end # Determines whether this node has a next node def next? not self.next.nil? end # Determines whether this node has a previous node def prev? not prev.nil? end # Determines whether this node has a last node def last? not last.nil? end # ------- Node Types ---------------- # Returns this node's type name def node_type_name case node_type # Most common choices first when ATTRIBUTE_NODE 'attribute' when DOCUMENT_NODE 'document_xml' when ELEMENT_NODE 'element' when TEXT_NODE 'text' # Now the rest when ATTRIBUTE_DECL 'attribute_decl' when CDATA_SECTION_NODE 'cdata' when COMMENT_NODE 'comment' when DOCB_DOCUMENT_NODE 'document_docbook' when DOCUMENT_FRAG_NODE 'fragment' when DOCUMENT_TYPE_NODE 'doctype' when DTD_NODE 'dtd' when ELEMENT_DECL 'elem_decl' when ENTITY_DECL 'entity_decl' when ENTITY_NODE 'entity' when ENTITY_REF_NODE 'entity_ref' when HTML_DOCUMENT_NODE 'document_html' when NAMESPACE_DECL 'namespace' when NOTATION_NODE 'notation' when PI_NODE 'pi' when XINCLUDE_START 'xinclude_start' when XINCLUDE_END 'xinclude_end' else raise(UnknownType, "Unknown node type: %n", node.node_type); end end # Specifies if this is an attribute node def attribute? node_type == ATTRIBUTE_NODE end # Specifies if this is an attribute declaration node def attribute_decl? node_type == ATTRIBUTE_DECL end # Specifies if this is an CDATA node def cdata? node_type == CDATA_SECTION_NODE end # Specifies if this is an comment node def comment? node_type == COMMENT_NODE end # Specifies if this is an docbook node def docbook_doc? node_type == DOCB_DOCUMENT_NODE end # Specifies if this is an doctype node def doctype? node_type == DOCUMENT_TYPE_NODE end # Specifies if this is an document node def document? node_type == DOCUMENT_NODE end # Specifies if this is an DTD node def dtd? node_type == DTD_NODE end # Specifies if this is an element node def element? node_type == ELEMENT_NODE end # Specifies if this is an entity node def entity? node_type == ENTITY_NODE end # Specifies if this is an element declaration node def element_decl? node_type == ELEMENT_DECL end # Specifies if this is an entity reference node def entity_ref? node_type == ENTITY_REF_NODE end # Specifies if this is a fragment node def fragment? node_type == DOCUMENT_FRAG_NODE end # Specifies if this is a html document node def html_doc? node_type == HTML_DOCUMENT_NODE end # Specifies if this is a namespace node (not if it # has a namepsace) def namespace? node_type == NAMESPACE_DECL end # Specifies if this is a notation node def notation? node_type == NOTATION_NODE end # Specifies if this is a processiong instruction node def pi? node_type == PI_NODE end # Specifies if this is a text node def text? node_type == TEXT_NODE end # Specifies if this is an xinclude end node def xinclude_end? node_type == XINCLUDE_END end # Specifies if this is an xinclude start node def xinclude_start? node_type == XINCLUDE_START end alias :child? :first? alias :children? :first? alias :child :first alias :each_child :each private def create_string_io(xml) result = StringIO.new("") if defined?(::Encoding) result.set_encoding(xml.encoding) end result end end end end libxml-ruby-5.0.3/lib/libxml/sax_parser.rb0000644000004100000410000000231614620142101020537 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class SaxParser # call-seq: # XML::SaxParser.file(path) -> XML::SaxParser # # Creates a new parser by parsing the specified file or uri. def self.file(path) context = XML::Parser::Context.file(path) self.new(context) end # call-seq: # XML::SaxParser.io(io) -> XML::SaxParser # XML::SaxParser.io(io, :encoding => XML::Encoding::UTF_8) -> XML::SaxParser # # Creates a new reader by parsing the specified io object. # # Parameters: # # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. def self.io(io, options = {}) context = XML::Parser::Context.io(io) context.encoding = options[:encoding] if options[:encoding] self.new(context) end # call-seq: # XML::SaxParser.string(string) # # Creates a new parser by parsing the specified string. def self.string(string) context = XML::Parser::Context.string(string) self.new(context) end end end endlibxml-ruby-5.0.3/lib/libxml/attributes.rb0000644000004100000410000000033714620142101020557 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Attributes def to_h inject({}) do |hash, attr| hash[attr.name] = attr.value hash end end end end endlibxml-ruby-5.0.3/lib/libxml/document.rb0000644000004100000410000001607114620142101020211 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Document # call-seq: # XML::Document.document(document) -> XML::Document # # Creates a new document based on the specified document. # # Parameters: # # document - A preparsed document. def self.document(value) Parser.document(value).parse end # call-seq: # XML::Document.file(path) -> XML::Document # XML::Document.file(path, encoding: XML::Encoding::UTF_8, # options: XML::Parser::Options::NOENT) -> XML::Document # # Creates a new document from the specified file or uri. # # Parameters: # # path - Path to file # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::Parser::Options. Mutliple options can be combined # by using Bitwise OR (|). def self.file(path, encoding: nil, options: nil) Parser.file(path, encoding: encoding, options: options).parse end # call-seq: # XML::Document.io(io) -> XML::Document # XML::Document.io(io, :encoding => XML::Encoding::UTF_8, # :options => XML::Parser::Options::NOENT # :base_uri="http://libxml.org") -> XML::Document # # Creates a new document from the specified io object. # # Parameters: # # io - io object that contains the xml to parser # base_uri - The base url for the parsed document. # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::Parser::Options. Mutliple options can be combined # by using Bitwise OR (|). def self.io(io, base_uri: nil, encoding: nil, options: nil) Parser.io(io, base_uri: base_uri, encoding: encoding, options: options).parse end # call-seq: # XML::Document.string(string) -> XML::Document # XML::Document.string(string, encoding: XML::Encoding::UTF_8, # options: XML::Parser::Options::NOENT # base_uri: "http://libxml.org") -> XML::Document # # Creates a new document from the specified string. # # Parameters: # # string - String to parse # base_uri - The base url for the parsed document. # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::Parser::Options. Mutliple options can be combined # by using Bitwise OR (|). def self.string(value, base_uri: nil, encoding: nil, options: nil) Parser.string(value, base_uri: base_uri, encoding: encoding, options: options).parse end # Returns a new XML::XPathContext for the document. # # call-seq: # document.context(namespaces=nil) -> XPath::Context # # Namespaces is an optional array of XML::NS objects def context(nslist = nil) context = XPath::Context.new(self) context.node = self.root context.register_namespaces_from_node(self.root) context.register_namespaces(nslist) if nslist context end # Return the nodes matching the specified xpath expression, # optionally using the specified namespace. For more # information about working with namespaces, please refer # to the XML::XPath documentation. # # call-seq: # document.find(xpath, nslist=nil) -> XML::XPath::Object # # Parameters: # * xpath - The xpath expression as a string # * namespaces - An optional list of namespaces (see XML::XPath for information). # # document.find('/foo', 'xlink:http://www.w3.org/1999/xlink') # # IMPORTANT - The returned XML::Node::Set must be freed before # its associated document. In a running Ruby program this will # happen automatically via Ruby's mark and sweep garbage collector. # However, if the program exits, Ruby does not guarantee the order # in which objects are freed # (see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17700). # As a result, the associated document may be freed before the node # list, which will cause a segmentation fault. # To avoid this, use the following (non-ruby like) coding style: # # nodes = doc.find('/header') # nodes.each do |node| # ... do stuff ... # end # # nodes = nil # GC.start def find(xpath, nslist = nil) self.context(nslist).find(xpath) end # Return the first node matching the specified xpath expression. # For more information, please refer to the documentation # for XML::Document#find. def find_first(xpath, nslist = nil) find(xpath, nslist).first end # Returns this node's type name def node_type_name case node_type when XML::Node::DOCUMENT_NODE 'document_xml' when XML::Node::DOCB_DOCUMENT_NODE 'document_docbook' when XML::Node::HTML_DOCUMENT_NODE 'document_html' else raise(UnknownType, "Unknown node type: %n", node.node_type); end end # :enddoc: # Specifies if this is an document node def document? node_type == XML::Node::DOCUMENT_NODE end # Specifies if this is an docbook node def docbook_doc? node_type == XML::Node::DOCB_DOCUMENT_NODE end # Specifies if this is an html node def html_doc? node_type == XML::Node::HTML_DOCUMENT_NODE end def dump warn('Document#dump is deprecated. Use Document#to_s instead.') self.to_s end def format_dump warn('Document#format_dump is deprecated. Use Document#to_s instead.') self.to_s end def debug_dump warn('Document#debug_dump is deprecated. Use Document#debug instead.') self.debug end def debug_dump_head warn('Document#debug_dump_head is deprecated. Use Document#debug instead.') self.debug end def debug_format_dump warn('Document#debug_format_dump is deprecated. Use Document#to_s instead.') self.to_s end def reader warn('Document#reader is deprecated. Use XML::Reader.document(self) instead.') XML::Reader.document(self) end end end end libxml-ruby-5.0.3/lib/libxml/namespaces.rb0000644000004100000410000000232014620142101020502 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Namespaces # call-seq: # namespace.default -> XML::Namespace # # Returns the default namespace for this node or nil. # # Usage: # doc = XML::Document.string('') # ns = doc.root.namespaces.default_namespace # assert_equal(ns.href, 'http://schemas.xmlsoap.org/soap/envelope/') def default find_by_prefix(nil) end # call-seq: # namespace.default_prefix = "string" # # Assigns a name (prefix) to the default namespace. # This makes it much easier to perform XML::XPath # searches. # # Usage: # doc = XML::Document.string('') # doc.root.namespaces.default_prefix = 'soap' # node = doc.root.find_first('soap:Envelope') def default_prefix=(prefix) # Find default prefix ns = find_by_prefix(nil) raise(ArgumentError, "No default namespace was found") unless ns Namespace.new(self.node, prefix, ns.href) end end end endlibxml-ruby-5.0.3/lib/libxml/schema/0000755000004100000410000000000014620142101017301 5ustar www-datawww-datalibxml-ruby-5.0.3/lib/libxml/schema/element.rb0000644000004100000410000000052314620142101021257 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Schema::Element def min_occurs @min end def max_occurs @max end def required? !min_occurs.zero? end def array? max_occurs > 1 end def elements type.elements end end end end libxml-ruby-5.0.3/lib/libxml/schema/attribute.rb0000644000004100000410000000040514620142101021630 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Schema::Attribute REQUIRED = 1 OPTIONAL = 2 def default node['default'] end def required? occurs == REQUIRED end end end end libxml-ruby-5.0.3/lib/libxml/schema/type.rb0000644000004100000410000000105614620142101020611 0ustar www-datawww-datamodule LibXML module XML class Schema::Type def kind_name Schema::Types.constants.find { |k| Schema::Types.const_get(k) == kind } end def annonymus_subtypes elements.select { |_, e| e.type.name.nil? } end def annonymus_subtypes_recursively(parent=nil) annonymus_subtypes.map do |element_name, e| [{[parent, element_name].compact.join('::') => e.type}, e.type.annonymus_subtypes_recursively(element_name)] end.flatten end end end end libxml-ruby-5.0.3/lib/libxml/hpricot.rb0000644000004100000410000000365114620142101020043 0ustar www-datawww-data# encoding: UTF-8 ## Provide hpricot API for libxml. Provided by Michael Guterl, ## inspired by http://thebogles.com/blog/an-hpricot-style-interface-to-libxml # #class String # def to_libxml_doc # xp = XML::Parser.new # xp.string = self # xp.parse # end #end # #module LibXML # module XML # class Document # alias :search :find # end # # class Node # # find the child node with the given xpath # def at(xpath) # self.find_first(xpath) # end # # # find the array of child nodes matching the given xpath # def search(xpath) # results = self.find(xpath).to_a # if block_given? # results.each do |result| # yield result # end # end # return results # end # # def /(xpath) # search(xpath) # end # # # return the inner contents of this node as a string # def inner_xml # child.to_s # end # # # alias for inner_xml # def inner_html # inner_xml # end # # # return this node and its contents as an xml string # def to_xml # self.to_s # end # # # alias for path # def xpath # self.path # end # # def find_with_default_ns(xpath_expr, namespace=nil) # find_base(xpath_expr, namespace || default_namespaces) # end # # def find_first_with_default_ns(xpath_expr, namespace=nil) # find_first_base(xpath_expr, namespace || default_namespaces) # end # ## alias_method :find_base, :find unless method_defined?(:find_base) ## alias_method :find, :find_with_default_ns ## alias_method :find_first_base, :find_first unless method_defined?(:find_first_base) ## alias_method :find_first, :find_first_with_default_ns ## alias :child? :first? ## alias :children? :first? ## alias :child :first # end # end #endlibxml-ruby-5.0.3/lib/libxml/attr.rb0000644000004100000410000000515714620142101017350 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Attr include Enumerable # call-seq: # attr.child? -> (true|false) # # Returns whether this attribute has child attributes. # def child? not self.children.nil? end # call-seq: # attr.doc? -> (true|false) # # Determine whether this attribute is associated with an # XML::Document. def doc? not self.doc.nil? end # call-seq: # attr.last? -> (true|false) # # Determine whether this is the last attribute. def last? self.last.nil? end # call-seq: # attr.next? -> (true|false) # # Determine whether there is a next attribute. def next? not self.next.nil? end # call-seq: # attr.ns? -> (true|false) # # Determine whether this attribute has an associated # namespace. def ns? not self.ns.nil? end # call-seq: # attr.namespacess -> XML::Namespaces # # Returns this node's XML::Namespaces object, # which is used to access the namespaces # associated with this node. def namespaces @namespaces ||= XML::Namespaces.new(self) end # # call-seq: # attr.parent? -> (true|false) # # Determine whether this attribute has a parent. def parent? not self.parent.nil? end # call-seq: # attr.prev? -> (true|false) # # Determine whether there is a previous attribute. def prev? not self.prev.nil? end # Returns this node's type name def node_type_name if node_type == Node::ATTRIBUTE_NODE 'attribute' else raise(UnknownType, "Unknown node type: %n", node.node_type); end end # Iterates nodes and attributes def siblings(node, &blk) if n = node loop do blk.call(n) break unless n = n.next end end end def each_sibling(&blk) siblings(self,&blk) end alias :each_attr :each_sibling alias :each :each_sibling def to_h inject({}) do |h,a| h[a.name] = a.value h end end def to_a inject([]) do |ary,a| ary << [a.name, a.value] ary end end def to_s "#{name} = #{value}" end end end endlibxml-ruby-5.0.3/lib/libxml/tree.rb0000644000004100000410000000177014620142101017332 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Tree # :nodoc: ELEMENT_NODE = Node::ELEMENT_NODE ATTRIBUTE_NODE = Node::ATTRIBUTE_NODE TEXT_NODE = Node::TEXT_NODE CDATA_SECTION_NODE = Node::CDATA_SECTION_NODE ENTITY_REF_NODE = Node::ENTITY_REF_NODE ENTITY_NODE = Node::ENTITY_NODE PI_NODE = Node::PI_NODE COMMENT_NODE = Node::COMMENT_NODE DOCUMENT_NODE = Node::DOCUMENT_NODE DOCUMENT_TYPE_NODE = Node::DOCUMENT_TYPE_NODE DOCUMENT_FRAG_NODE = Node::DOCUMENT_FRAG_NODE NOTATION_NODE = Node::NOTATION_NODE HTML_DOCUMENT_NODE = Node::HTML_DOCUMENT_NODE DTD_NODE = Node::DTD_NODE ELEMENT_DECL = Node::ELEMENT_DECL ATTRIBUTE_DECL = Node::ATTRIBUTE_DECL ENTITY_DECL = Node::ENTITY_DECL NAMESPACE_DECL = Node::NAMESPACE_DECL XINCLUDE_START = Node::XINCLUDE_START XINCLUDE_END = Node::XINCLUDE_END DOCB_DOCUMENT_NODE = Node::DOCB_DOCUMENT_NODE end end endlibxml-ruby-5.0.3/lib/libxml/parser.rb0000644000004100000410000000776114620142101017675 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Parser # call-seq: # XML::Parser.document(document) -> XML::Parser # # Creates a new parser for the specified document. # # Parameters: # # document - A preparsed document. def self.document(doc) context = XML::Parser::Context.document(doc) self.new(context) end # call-seq: # XML::Parser.file(path) -> XML::Parser # XML::Parser.file(path, encoding: XML::Encoding::UTF_8, # options: XML::Parser::Options::NOENT) -> XML::Parser # # Creates a new parser for the specified file or uri. # # Parameters: # # path - Path to file # base_uri - The base url for the parsed document. # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::Parser::Options. Mutliple options can be combined # by using Bitwise OR (|). def self.file(path, base_uri: nil, encoding: nil, options: nil) context = XML::Parser::Context.file(path) context.base_uri = base_uri if base_uri context.encoding = encoding if encoding context.options = options if options self.new(context) end # call-seq: # XML::Parser.io(io) -> XML::Parser # XML::Parser.io(io, encoding: XML::Encoding::UTF_8, # options: XML::Parser::Options::NOENT # base_uri: "http://libxml.org") -> XML::Parser # # Creates a new parser for the specified io object. # # Parameters: # # io - io object that contains the xml to parser # base_uri - The base url for the parsed document. # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::Parser::Options. Mutliple options can be combined # by using Bitwise OR (|). def self.io(io, base_uri: nil, encoding: nil, options: nil) context = XML::Parser::Context.io(io) context.base_uri = base_uri if base_uri context.encoding = encoding if encoding context.options = options if options self.new(context) end # call-seq: # XML::Parser.string(string) # XML::Parser.string(string, encoding: XML::Encoding::UTF_8, # options: XML::Parser::Options::NOENT # base_uri: "http://libxml.org") -> XML::Parser # # Creates a new parser by parsing the specified string. # # Parameters: # # string - The string to parse # base_uri - The base url for the parsed document. # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::Parser::Options. Multiple options can be combined # by using Bitwise OR (|). def self.string(string, base_uri: nil, encoding: nil, options: nil) context = XML::Parser::Context.string(string) context.base_uri = base_uri if base_uri context.encoding = encoding if encoding context.options = options if options self.new(context) end def self.register_error_handler(proc) warn('Parser.register_error_handler is deprecated. Use Error.set_handler instead') if proc.nil? Error.reset_handler else Error.set_handler(&proc) end end end end endlibxml-ruby-5.0.3/lib/libxml/html_parser.rb0000644000004100000410000000767514620142101020725 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class HTMLParser # call-seq: # XML::HTMLParser.file(path) -> XML::HTMLParser # XML::HTMLParser.file(path, encoding: XML::Encoding::UTF_8, # options: XML::HTMLParser::Options::NOENT) -> XML::HTMLParser # # Creates a new parser by parsing the specified file or uri. # # Parameters: # # path - Path to file to parse # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::HTMLParser::Options. Mutliple options can be combined # by using Bitwise OR (|). def self.file(path, encoding: nil, options: nil) context = XML::HTMLParser::Context.file(path) context.encoding = encoding if encoding context.options = options if options self.new(context) end # call-seq: # XML::HTMLParser.io(io) -> XML::HTMLParser # XML::HTMLParser.io(io, encoding: XML::Encoding::UTF_8, # options: XML::HTMLParser::Options::NOENT # base_uri: "http://libxml.org") -> XML::HTMLParser # # Creates a new reader by parsing the specified io object. # # Parameters: # # io - io object that contains the xml to parser # base_uri - The base url for the parsed document. # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::HTMLParser::Options. Mutliple options can be combined # by using Bitwise OR (|). def self.io(io, base_uri: nil, encoding: nil, options: nil) context = XML::HTMLParser::Context.io(io) context.base_uri = base_uri if base_uri context.encoding = encoding if encoding context.options = options if options self.new(context) end # call-seq: # XML::HTMLParser.string(string) # XML::HTMLParser.string(string, encoding: XML::Encoding::UTF_8, # options: XML::HTMLParser::Options::NOENT # base_uri: "http://libxml.org") -> XML::HTMLParser # # Creates a new parser by parsing the specified string. # # Parameters: # # string - String to parse # base_uri - The base url for the parsed document. # encoding - The document encoding, defaults to nil. Valid values # are the encoding constants defined on XML::Encoding. # options - Parser options. Valid values are the constants defined on # XML::HTMLParser::Options. Mutliple options can be combined # by using Bitwise OR (|). def self.string(string, base_uri: nil, encoding: nil, options: nil) context = XML::HTMLParser::Context.string(string) context.base_uri = base_uri if base_uri context.encoding = encoding if encoding context.options = options if options self.new(context) end # :enddoc: def file=(value) warn("XML::HTMLParser#file is deprecated. Use XML::HTMLParser.file instead") @context = XML::HTMLParser::Context.file(value) end def io=(value) warn("XML::HTMLParser#io is deprecated. Use XML::HTMLParser.io instead") @context = XML::HTMLParser::Context.io(value) end def string=(value) warn("XML::HTMLParser#string is deprecated. Use XML::HTMLParser.string instead") @context = XML::HTMLParser::Context.string(value) end end end end libxml-ruby-5.0.3/lib/libxml/namespace.rb0000644000004100000410000000257714620142101020335 0ustar www-datawww-data# encoding: UTF-8 module LibXML module XML class Namespace include Comparable include Enumerable # call-seq: # namespace1 <=> namespace2 # # Compares two namespace objects. Namespace objects are # considered equal if their prefixes and hrefs are the same. def <=>(other) if self.prefix.nil? and other.prefix.nil? self.href <=> other.href elsif self.prefix.nil? -1 elsif other.prefix.nil? 1 else self.prefix <=> other.prefix end end # call-seq: # namespace.each {|ns| .. } # # libxml stores namespaces in memory as a linked list. # Use the each method to iterate over the list. Note # the first namespace in the loop is the current namespace. # # Usage: # namespace.each do |ns| # .. # end def each ns = self while ns yield ns ns = ns.next end end # call-seq: # namespace.to_s -> "string" # # Returns the string represenation of a namespace. # # Usage: # namespace.to_s def to_s if self.prefix "#{self.prefix}:#{self.href}" else self.href end end end end endlibxml-ruby-5.0.3/lib/xml.rb0000644000004100000410000000072014620142101015676 0ustar www-datawww-data# encoding: UTF-8 # This file loads libxml and adds the LibXML namespace # to the toplevel for conveneience. The end result # is to have XML:: universally exposed. # # It is recommend that you only load this file for libs # that do not have their own namespace, eg. administrative # scripts, personal programs, etc. For other applications # require 'libxml' instead and include LibXML into your # app/libs namespace. require 'libxml' include LibXMLlibxml-ruby-5.0.3/lib/xml/0000755000004100000410000000000014620142101015352 5ustar www-datawww-datalibxml-ruby-5.0.3/lib/xml/libxml.rb0000644000004100000410000000020314620142101017161 0ustar www-datawww-data# encoding: UTF-8 # This is here for backward compatibility. # # TODO: DEPRECATE! require 'libxml.rb' include LibXML libxml-ruby-5.0.3/lib/libxml.rb0000644000004100000410000000014514620142101016366 0ustar www-datawww-data# encoding: UTF-8 # # This include is deprecated, use libxml-ruby instead! require 'libxml-ruby'libxml-ruby-5.0.3/lib/libxml-ruby.rb0000644000004100000410000000126514620142101017351 0ustar www-datawww-data# encoding: UTF-8 # Load the C-based binding. begin RUBY_VERSION =~ /(\d+.\d+)/ require "#{$1}/libxml_ruby" rescue LoadError require "libxml_ruby" end # Load Ruby supporting code. require 'libxml/error' require 'libxml/parser' require 'libxml/document' require 'libxml/namespaces' require 'libxml/namespace' require 'libxml/node' require 'libxml/attributes' require 'libxml/attr' require 'libxml/attr_decl' require 'libxml/tree' require 'libxml/html_parser' require 'libxml/sax_parser' require 'libxml/sax_callbacks' #Schema Interface require 'libxml/schema' require 'libxml/schema/type' require 'libxml/schema/element' require 'libxml/schema/attribute' libxml-ruby-5.0.3/HISTORY0000644000004100000410000010367314620142101015102 0ustar www-datawww-data= Release History == 5.0.3 / 2024-03-11 * Update xmlStructuredErrorFunc to be backwards compatible == 5.0.2 / 2024-01-08 * Fix broken DTD creation (DTD name is not required) == 5.0.1 / 2024-01-08 * Fix broken Document#io method that was broken by switching Parsers to use keyword arguments == 5.0.0 / 2024-01-07 * This release is major version bump because it removes access to global parser options that libxml2 version 2.12.0 deprecated (see https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.12.0) In the unlikely event your code uses these options, then you will need to update it. Specifically, instead of setting global parser options, pass them directly to either Parsers or ParserContexts when creating them. Options are defined as constants in LibXML::XML::Parser::Options and LibXML::HTML::Parser::Options * Update Parser initialize methods to take keyword parameters instead of a hash table (you may have to update your code due to this change) * Fix broken compilation with libxml2 version 2.12.0 (due to libxml2 header changes) * Add support for Ruby 3.3.* * Remove support for Ruby 2.7.* (gem should still work but is no longer tested) == 4.1.2 / 2023-11-04 * Fix Ruby warnings about undefined allocators (yuuji.yaginuma, Christopher Sahnwaldt) * Fix Schema::Element required? and array? (John Andrews) * Remove SchemaElement#minOccurs and SchemaElement#maxOccurs since they actually did not work (Charlie Savage) * Fix typo: XPatch -> XPath (Christopher Sahnwaldt) * Introduce new alternative Homebrew installation search paths to extconf makefile (Pierce Brooks) == 4.1.1 / 2023-05-01 * Fix compile warning (or error) for input_callbacks_register_input_callbacks (Charlie Savage) * Remove call to deprecated function htmlDefaultSAXHandlerInit (Charlie Savage) == 4.1.0 / 2023-04-30 * Fix compile warning (or error) for rxml_encoding_to_rb_encoding (Charlie Savage) * Breaking - Remove LibXML::XML.features since its uses functionality deprecated in LibXML (Charlie Savage) == 4.0.0 / 2022-12-28 * Breaking - Remove support for XPointer since libxml2 has deprecated it and will remove it (Charlie Savage) * Breaking - Remove support for ancient setup.rb script (Charlie Savage) == 3.2.4 / 2022-10-29 * Support libxml2 version 2.10.2 (Charlie Savage) * Reduce number of globally included C header files (Charlie Savage) == 3.2.3 / 2022-05-22 * Change some getter methods to instance variables with attr_accessors for easier debuggability (David Hansen) * Add a number of tests related to schemas (David Hansen) * Add schema.imported_elements so we can find imported elements (David Hansen) * Fix segfault under windows when dereferencing a pre-existing error where the node has already been freed (David Hansen) * Update to change name from imported_elements to imported_ns_elements and return a hash of hashes for namespaced elements (David Hansen) * Only call xmlGetFeaturesList if LIBXML_LEGACY_ENABLED is defined. Most distros still ship libxml2 with legacy features enabled, but this will change (Nick Wellnhofer) * Update GitHub Actions to use ruby/setup-ruby (Greg) * Fix memory leak in rxml_node_path, node.path (vovanmozg) == 3.2.2 / 2022-01-15 * Switch to Github actions for CI/CD (Greg) * Test fixes (Greg, Sergio Durigan Junior) * Fix typo on test/test_sax_parser.rb (Sergio Durigan Junior) * Update homepage in gemspec (Pirate Praveen Arimbrathodiyil) == 3.2.1 / 2020-11-05 * Fix incorrect handling of encodings when using XMLWriter.io (Charlie Savage) * Clean up README (Richard Michael) == 3.2.0 / 2020-05-09 Charlie Savage * Fix crash when creating an empty DTD * Modernize tests to use Bundler to load gem * Add libxml-ruby.rb file so gem loads in expected way. * Add support for xmlSaveNoEmptyTags. * Clean up extconf.rb file == 3.1.0 / 2018-02-03 Charlie Savage * Fix segmentation fault when adding one node to another node (Charlie Savage) * Fix deprecated "assert_equal(nil, expected)" calls. #148 and #151. (utilum) * Remove assigned but unused variables. #150 (utilum) * Add Gemfile. #146. (Dorian Marié) * Remove duplicate hash key in setup.rb. #147. (Dorian Marié) * Fix gemspec by requiring Date. #149 (utilum) * Restore default internal encoding after tests are completed. #123 (Charlie Savage) * Remove duplicate method definitions. #145. (Charlie Savage) * Remove SchemaElement#minOccurs and SchemaElement#maxOccurs since they actually did not work (Charlie Savage) * Rename test files to follow Ruby conventions (Charlie Savage) * Fix handling of node returned by Reader#expand. #142. (Charlie Savage) * Add Travis Build support (Charlie Savage) * Fix Fixnum deprecation (Charlie Savage) * Cleanup schema code (Charlie Savage) * Update Visual Studio project to 2017 (Charlie Savage) == 3.0.0 / 2017-02-07 Charlie Savage * Revamp how libxml-ruby manages memory. Instead of trying to return the same ruby object for each xmlnode, the bindings now create wrapper ruby objects as needed which are then freed at the end of use. This allows most memory management to be handled by libxml itself. Ruby only manages the lifespan of documents and parent xml nodes. When those go out of scope, the underlying libxml objects are also freed. This implementation requires almost no overhead, plays nicely with Nokogiri and appears to work much better (Charlie Savage). * Change XML::Node#eql? API. Nodes are now considered equal only if they wrap the same underlying libxml node. Previously, they would also be considered equal if they contained the same content (Charlie Savage) * Change XML::Reader.expand API. Previously it would automatically instantiate a reader document so the an xpath expression could be used to search the returned node. Now you should first call reader.doc (Charlie Savage) * Update Visual Studio project for Visual Studio 15 - requires ruby 2.4+ (Charlie Savage) * Remove APIs that have been deprecated for several years (Charlie Savage) == 2.9.0 / 2016-06-13 Charlie Savage * Revamp libxml-ruby's memory management to not cause crashes when used with Nokogiri (James Laird-Wah) * Fix garbage collection issue that sometimes caused the library to hang (Charlie Savage) * Improved multi-threading support (Charlie Savage) * Fix crash sometimes caused by a xml node being being freed twice (Charlie Savage) * Fix memory leak when setting the text content of a node (Charlie Savage) * Set a default task in the Rakefile - use "test" (Robert Haines) * Add "hanna_gudao" gem and add "rake-compiler" to develpoment dependencies (Robert Haines) * Use Process.getrlimit instead of `ulimit` in the tests (Robert Haines) * Build on smartos (Steven Williamson) * Fix compiler warnings (Charlie Savage) * Add Xcode project for easier debugging on OSX (Charlie Savage) * Switch from unit test to minitest (Charlie Savage) == 2.8.0 / 2015-01-09 Charlie Savage * Use RbConfig instead of Config in extconf.rb (Robert Haines) * Correct xpath documentation XML (Bill Mill) * Correct from_string method documentation (Bill Mill) * Fix compile error with debug not enabled in libxml (Patrick Ziegler) * Update gemspec to include license (Charlie Savage) * In XML::Writer prevent writing to io while being GCed (Brett Gibson) == 2.7.0 / 2013-08-13 Charlie Savage * Don't call rb_warning in GC mark function (Dirkjan Bussink) * Set libxml error handler when a libxml-ruby error handler is set (Geoffrey Giesemann) * Fix tests for nil TypeErrors for ruby 2.0=< (Geoffrey Giesemann) * Fix segmentation fault for issue #62 (Charlie Savage) * Add #node_type method to dtd (Charlie Savage) * Fixing equality check of LibXML::XML::Error against other objects (MichaÅ‚ Szajbe) * Fix #63, XML::Writer.set_quote_char UT, wrong expected string (julp) * Fix potential segfault when GC occurs while creating ns from xpath (Timothy Elliott) * Fix for #59, segmentation fault after failure to load external schema (Clifford Heath) == 2.6.0 / 2013-02-16 Charlie Savage * Fix uninitialized constant LibXML::XML::Error::I18N (NameError) that occurred with older versions of libxml. * Various updates/fixes to new XML::Writer class and update how flushing works (julp) == 2.5.0 / 2013-01-27 Charlie Savage * Compatibility with older versions for IO::write (rb_io_bufwrite is specific to ruby >= 1.9.3?) and symbols are VALUE not ID (julp). * Fix version for xmlTextWriterSetQuoteChar, it appeared in libxml2 2.9.0, last version (julp) * Update use of LIBXML_VERSION (julp). * Fix misuse of rb_scan_args (julp). * Update documentation, including DTD docs and added XML Writer (julp). * Added a new XML::Writer class (julp). * Improved xml reader api and add namespace support. Note that passing a numeric value to XML::Reader::move_to_attribute has been deprecated. Instead you should now use #move_to_attribute_no. (julp). * Improve error handling and messages (Jarl Friis) == 2.4.0 / 2012-12-14 Charlie Savage * Support libxml 2.9.0 (Daniel Veillard) * Extensive new interfaces for xml schema functionality including suppor for schemal elements, types, facets and attributes (Anton Sozontov) * Fix Encoding#from_s bug and update docs (Nikita Afanasenko) * Node#content= encoding (Nikita Afanasenko) == 2.3.3 / 2012-07-01 Charlie Savage * Add LibXML::XML::Error.get_handler (Carsten Zimmermann) * Fix variable name in example (Marcus) == 2.3.2 / 2012-03-20 Charlie Savage * Define various canonicalize constants to support libxml2 versions older than 1.1.25 (thanks Apple!) == 2.3.1 / 2012-03-20 Charlie Savage * Yanked - didn't fix the OSX canonicalize issue == 2.3.0 / 2012-03-18 Charlie Savage * Add ability to insert new PI-nodes into the xmltree (Axel Struebing). * Added full pass-through access to libxml2 xmlC14NDocDumpMemory method via LibXML::XML::Document#canonicalize method with optional arguments. * Added full test data for C14N based off of W3C spec. (http://www.w3.org/TR/xml-c14n#Examples) * Update sax handler to support encodings on Ruby 1.9 and higher. == 2.2.2 / 2011-08-29 Charlie Savage * ++API CHANGE+++ Reader#relax_ng_validate now takes a RelaxNG object. This is what the documentation has always said it takes, but it previously took a string. In addition, it now returns true or false instead of 0 or -1. Reader#schema_validate now takes a Schema object. This is what the documentation has always said it takes, but it previously took a string. In addition, it now returns true or false instead of 0 or -1. Fixes GitHub issue #30. * Added Parser::Context#close and HTMLParser::Context#close methods that allow the underlying io stream (file, string, etc) to be closed. Once a parser is done parsing its data, it now calls one of these methods. This means that if you parse thousands of files at the same time, without running Ruby's garbage colllector, you won't get a too many files open error. Fixes GitHub issue #29. * Fixed bug where Node#inner_xml caused an error when it had no child nodes. Fixes GitHub issues #31 * Don't require 'rake' in the gemspec to avoid annoying Bundler bugs == 2.2.1 / 2011-08-13 Charlie Savage * Packaging fix - include the custom .def file in the gem. == 2.2.0 / 2011-08-09 Charlie Savage * Update encoding support for Ruby 1.9 so that libxml-ruby returns strings encoded in UTF-8. This change was required since libxml internally stores strings in UTF-8. The exceptions to this rule are the #to_s methods which return UTF-8 by default but can return other encodings if requested. == 2.1.2 / 2011-08-03 Charlie Savage * Fix segmentation fault that could occur when an XPathContext was marked before it was fully initialized (Charlie Savage). * Add mark method to document to mark all nodes currently being accessed by ruby. This make Ruby Enterprise Edition happy (Charlie Savage). == 2.1.1 / 2011-07-31 Charlie Savage * Switch to using def files to control library exports (Charlie Savage). == 2.1.0 / 2011-07-31 Charlie Savage * Ruby 1.9.3 compatability (Charlie Savage). * Added XPath expression <-> Ruby value conversion methods (Jens Wille). * Extracted rxml_xpath_to_value from rxml_xpath_context_find (Jens Wille). * Adapted rxml_xpath_from_value from Gregoire Lejeune's ruby-xslt library, see https://github.com/glejeune/ruby-xslt (Jens Wille). * Allow calling #find on nodes returned from Reader (Charlie Savage). * Change document handling in XPath::Context to address segmentation fault on Ruby Enterprise Edition (Charlie Savage). * Update gemspec file to work directly with bundler thereby allowing git repository to be used as gem (Charlie Savage). * Support gem buld (Charlie Savage). * Simplify memory management of attributes namespaces to fix segmentation faults that occurred when using Ruby 1.9.3 (Charlie Savage). == 2.0.8 / 2011-06-23 Charlie Savage * Add in 2 new HTML Parser constants - NODEFDTD and NOIMPLIED. * Fix compile issue on Ruby 1.9.3 == 2.0.6 / 2011-05-23 Charlie Savage * Fix segfault that sometimes occurred when looking up encodings on 1.9. In some cases the Ruby encoding infrastructure was not properly initialized (nkriege). == 2.0.5 / 2011-05-05 Charlie Savage * Document#validate_dtd would sometimes cause segmentation faults due to an improperly initialized data structure (Charlie Savage) == 2.0.4 / 2011-05-02 Charlie Savage * Fix compile issues on platforms using older versions of libxml2. The problem as using a C14N constants that was added to libxml2 in July 2009 (Charlie Savage). == 2.0.3 / 2011-05-01 Charlie Savage * The biggest change in this release is supporting the use of libxml-ruby in native background Ruby threads. Previously, the use of libxml-ruby in background threads in Ruby 1.9.x and higher would often cause segmentation faults. This has now been fixed (Charlie Savage). * Update Reader#expand so that returned node correctly remembers its encoding in Ruby 1.9.x (zerebubuth). * Add check to verify a node has not been deleted. This can happen when a ruby variable holds a reference to a child node that gets freed when its parent gets freed. Previously when this happened a segmentation fault would occur, now an exception is raised (Charlie Savage, fixes RubyForge #26839. * Do not unlink nodes before internal validations have run - avoids segmentation faults caused by freeing a node twice (Charlie Savage). * Add support for Document#canonicalization (Victor Lin). * Fix memory leak in Reader#lookup_namespace (Charlie Savage). * Fix memory leak in Reader#[] (Nathan Kriege). * Fix usage of @io instance variable (Jeffrey Taylor) * Removed old sax error handling code that has been fixed in newer versions of libxml (Charlie Savage). * Code cleanup - remove unused variables and commented out code (Charlie Savage) * Minor text changes and documentation fixes (Charlie Savage). * Fix documentation error (fixes RubyForge #26888). * Update documentation for Document#validation* methods (fixes RubyForge #24833). * Update documentation and test (fixes Ruby Forge Issue #28770). * Updated documentation in README (Anurag Priyam): 1. rake doc does not work; use rake rdoc. 2. gem mislav-hanna does not exist; use hanna. 3. rake rdoc 'depends' on hanna; no need of RDOCOPTS 4. Point to the github issue tracker instead of Ruby Forge 5. Point to the github (gh-pages) site for docs * Add tc_error to test suite (Charlie Savage). * Add sax test (Stanislav O.Pogrebnyak). == 2.0.2 / 2011-04-17 Charlie Savage * Added binaries for windows (Charlie Savage). * Update Ruby 1.9 encoding handling to support libxml versions older than version 2.6.26 which was released on June 6, 2006 (Charlie Savage). * Add publish_with_docs rake task - combines publishing the website and docs (Anurag Priyam). * Correctly copy the documentation directory (Anurag Priyam) * Use relative link for rdoc so the links are correct on both rubyforge and github (Anurag Priyam). * Update Rakefile to use Hanna RDco template (Charlie Savage). * Update dates on license file (Charlie Savage). * Add api to allow setting of attribute namespaces. Fixes issue #10 (Charlie Savage). * Remove old hack to call the on_error method. This hack isn't needed anymore since a better workaround was put in place in the parser context. Fixes This fixes issue #12 (Charlie Savage). * Remove references to passing blocks to validation functions. The blocks are no longer called since the bindings use libxml's structured error handling. See issue #6 (Charlie Savage). * Fix up comment in Document and Node. See issue #8 (Charlie Savage). * Update website text (Charlie Savage). == 2.0.0 / 2011-04-16 Charlie Savage * Ruby 1.9.2 support. The biggest addition is encoding support. Strings returned by the libxml bindings are now set to the encoding of the underlying xml document (Charlie Savage). * Rubinius compatability. Removed unnecessary use of RHASH_TBL (Aman Gupta) * Added .gemspec file (Dudley Flanders). * Updated Windows checks to take into account mingw32 (Yaohan Chen). * Fix memory leak in Reader#Expand (Szymon Nowak). * Fix memory leaks in Reader#read_string, Reader#read_inner_xml and Reader#read_outer_xml (Sean Geoghegan). * Node#space_preserve= was backwards (Dudley Flanders) * Fixed typo in readme, added rdoc extension (Loren Sands-Ramshaw). * Switched to Rake Compiler (Charlie Savage). * Use xmlMalloc() memory for ctxt->sax structure. Sometimes the ctxt->sax pointer may not be zeroed in rxml_sax_parser_parse(), for example when exception is raised in one of callbacks. This lets xmlFreeParserCtxt() clean this up (Alexey I. Froloff). * Added a rake task to publish the website to github. Moved the jekyll website to web directory (Anurag Priyam). * Modernize project metadata and layout (7rans) == 1.1.3 / 2009-03-18 Charlie Savage * Improve performance 10 to 20% by turning on libxml2's dictionary feature that allows parsers to reuse previously parsed strings. * Fix XML::Node#remove! to work correctly with libxml's dictionary feature. * Correctly set up parser context options. * Simplify DOM modification code (Node#next=, Node#prev=, Node#sibling=) and update documentation. * Deprecated Node#add_child and Node#child=, use Node#<< instead * Fix documentation for Node#<< * Added Document#import to enable moving nodes from one document to another document. == 1.1.2 / 2009-03-12 Charlie Savage * Added XML::Node#inner_xml helper method. * Fix segmentation that could occur when calling the mark function on a previously freed node. == 1.1.1 / 2009-03-10 Charlie Savage * Fix - Only include extra html parser context methods for versions of libxml older than 2.6.27. == 1.1.0 / 2009-03-09 Charlie Savage * Fix bug caused by the mark function being called on partially initialized attributes. * Revert back to libxml2's internal memory manager. == 1.0.0 / 2009-03-05 Charlie Savage * OS X (Charlie Savage). Update bindings to support the default installed version of libxml2 (2.6.16) on OS X 10.5 and the latest version available via MacPorts. == 0.9.9 / 2009-03-05 Charlie Savage * Ruby 1.9.1 support (Charlie Savage). libxml-ruby now compiles and runs on either 1.8.6 and 1.9.1. With 1.8.6 all tests should pass while on 1.9.1 all but for encoding tests pass. The port to Ruby 1.9.1 revealed two memory allocation bugs (one with dtds, one with nodes) which are now fixed. * Better OS X support (Joe Khoobyar). The default version of libxml2 on OS X 10.5 is fairly old, resulting in this link error: NSLinkModule() error dyld: Symbol not found: _htmlNewParserCtxt This can be fixed by using MacPorts to get a newer version of libxml2. To make use of MacPorts, the build script has been updated to use xml2-config. This can be fine-tuned using the new --with-xml2-config / --without-xml2-config options to extconf.rb (default is --without-xml2-config to match existing behavior). * Greatly reduced memory usage (Joe Khoobyar). See http://rubyforge.org/pipermail/libxml-devel/2009-February/001375.html. * Add Document#xhtml? and document#node_type methods (Joe Khoobyar) * Add XPath::Object#last (Joe Khoobyar) * Provide finer control over CDATA nodes on a parser by parser basis (Joe Khoobyar). * Bug fix - Namespaces were incorrectly merged with attributes in the new sax2 handler (Charlie Savage). * Bug fix - Support iterating over nodes and attributes even with blocks that call remove! (Charlie Savage) * Bug fix - If reader.node is NULL, return nil instead of crashing (Charlie Savage) * Bug fix - Dtd's owned by documents were freed twice in some circumstances (Joe Khoobyar). * Bug fix - Fix output escaping on attributes nodes (Joe Khoobyar). * Bug fix - Make sure IO objects are not garbage collected when used as parser sources (Charlie Savage). == 0.9.8 / 2009-1-24 Charlie Savage * Refactored XML::Parser, XML::HTMLParser, XML::SaxParser and XML::Reader to have consistent APIs. All the parsers now take a context object in their constructors, allowing fine grained control over the parsers for advanced use cases. These API changes are backwards compatible except for XML::Reader, which now takes an optional hash table as a second parameter in its various constructors versus an optional boolean value. * Updated all APIs to use the encoding constants defined in XML::Encoding versus string values. This API change is not backwards compatible. * Added support for attribute declarations in DTD's via the new XML::AttrDecl class (Len Lattanzi) * Support libxml's content escaping capabilities for text nodes by wrapping libxml's "xmlStringText" and "xmlStringTextNoenc" (Joe Khoobyar). * Updated XML::Reader#read API to return true if a node was read, false if node was not read and raises an exception on an error. Previously #read returned 1 if a node was read, 0 if a node was not read and -1 for an error. This change is not backwards compatible, but provides a more natural interface for Ruby by allowing code like this: while reader.read # do stuff end * Changed XML::Error exception objects to return copies of nodes that cause parse errors instead of the original node. This prevents segmentation faults when the error is reraised. * Added XML::Reader#node method. * Fixed compile errors on OS X which uses an older version of libxml. * Fixed memory leak when performing XPath searches. * Fixed rdocs. * Don't override libxml's default settings for entity substitution and loading external DTDs. This may break some code - you may need to add in a call to XML.default_substitute_entities = true or XML.default_load_external_dtd = true. == 0.9.7 / 2008-12-08 Charlie Savage * Added SAX2 support. SAX handlers now define two new callbacks, on_start_element_ns and on_end_element_ns methods. These new callbacks support namespaces, making them superior to the older callbacks on_start_element and on_end_element methods. The old callbacks are still supported, but may be deprecated in the future depending on community feedback. * Added SAX support for libxml's structured error handling. That menas sax handlers now define a new callback, on_error, which takes one parameter, an instance of XML::Error. The older on_parser_error, on_parser_warning and on_parser_fatal_error callbacks are no longer suported so you must port your code. Note that the older callbacks took one string parameter, instead of an XML::Error object. * Experimental work-around for libxml error handling bug - see http://mail.gnome.org/archives/xml/2008-December/msg00014.html for more information. * Fix compilation bugs on Solaris. * Fix Rdoc compilation bug. == 0.9.6 / 2008-12-08 Charlie Savage * Refactored namespace handling. The existing, and inconsistent, namespace methods defined on XML::Node have been deprecated. They have been replaced by a the new XML::Namespaces class. Use this class to inspect a node's namespace, its default namespace, its namespace definitions and which namespaces are in scope. It can be accessed via the the XML::Node#namespaces method. * Rationalized XML::Document#save, XML::Document#to_s and XML::Node#to_s to take an optional hash table of parameters that control how output is generated. Supported parameters include setting indentation on or off, the indentation level and the output encoding. This is an API change and may break existing calls to XML::Document#save. However, the previous API was broken - setting the encoding resulted in an error so its unlikely anyone is using it. * Rationalized XML::Document#debug, XML::Node#debug, XML::XPath::XPathObject#Debug. * Deprecated a number of duplicate dump* and debug_* methods in XML::Document and XML::Node. * Additional Ruby 1.9.1 compatability fixes. * Cleaned up header file guards. == 0.9.5 / 2008-11-29 Charlie Savage * Ruby 1.9.1 preview release compatability (Felipe Contreras) * Update Node#remove! to return the removed node and to set its document to nil. This allows the node to be either moved to another document, another part of the same document or to be freed on the next garbage collection once its references have gone out of scope. * Fix bug where XPathExpression#compile mistakenly overwrote RegExp#compile. * Update Node to use standard ruby allocators and initializers. * Update HTML parser to be more forgiving of invalid documents. * Update include paths for Darwin Ports on OS X. * Updated C code base to use BSD/Allman style == 0.9.4 / 2008-11-24 Charlie Savage * Update HTML parser so that it can read files, strings and io streams. * Update HTML parser to support user specified encodings. * Additional C code cleanup. == 0.9.3 / 2008-11-22 Charlie Savage * Fixed segmentation fault caused by documents being freed before xpath results that referenced the document (take 2). * Allowed sax parser to use io stream * Combined encoding and input classes * Cleaned up C code - removed remaining legacy structures, added static to most methods, changed C namespace from ruby_xml to rxml == 0.9.2 / 2008-11-19 Charlie Savage * Add support for compiled XPath expressions (donated by Pavel Valodzka) * Fixes for compiling on OS X 10.5.4 and 10.5.5 == 0.9.1 / 2008-11-18 Charlie Savage * Expose LibXML's encoding support via a new Encoding object. * Revamp error handling to be much easier to use. Errors are now wrapped by the new XML::Error class and are thrown as exceptions when it is appropriate. * Fixed segmentation fault caused by documents being freed before xpath results that referenced the document. * Add Node#register_default_namespace to simplify default namespace handling. * Significantly improve documentation * A number of bug fixes and patches. == 0.9.0 / 2008-11-18 Charlie Savage * Version 0.9.0 was removed due to packaging errors. == 0.8.3 / 2008-07-21 Charlie Savage * Missed several files in last release == 0.8.2 / 2008-07-21 Charlie Savage * To use LibXML you can either require 'xml' or require 'libxml'. The differences is that require 'xml' mixes the LibXML module into the global namespace, thereby allowing you to write code such as document = XML::Document.new. Note that this is different from 0.8.0 and 0.8.1 and may require updating your code. * Support RelaxNG validation (thanks to Morus Walter) * Support passing IO objects to XmlReaders (thanks to Tom Hughes) * Fix segmentation fault caused by adding an attribute to a CDATA node * Moved node checking functions from C to Ruby * Improved Windows support - libxml-ruby should now work out of the box. * Improved Windows support - turned on libxml's zlib and iconv support. == 0.8.1 / 2008-07-09 Charlie Savage * Reimplmented Node#each_attr for backwards compatability * Moved node type test to Ruby. == 0.8.0 / 2008-07-09 Charlie Savage * Fixed bug in returning attributes from XPath results * Fixed DOM traversal methods * Changed Node#children to return an array of nodes * Fixed bug in returning attributes from XPath results * Refactored XPath support, providing more user hooks in the XPath::Context class * Added Node#properties for backwards compatibility * Updated setup.rb * Added more tests * Updated rdocs and README file * Moved libxml into LibXML namespace == 0.7.0 / 2008-07-09 Charlie Savage * Added new attributes class to provide a more natural way of working with attributes * Fixed XML::Attr to better support namespaces * Added documentation on how to use namespaces with XPath * Removed allocation of extraneous structures used to wrap nodes, namespaces and attributes * Cleaned up tests and added new test suite * Updated rdocs and README file * Cleaned out most of the bug list == 0.6.0 / 2008-07-01 Charlie Savage * Fixed memory allocation errors in Windows. On Windows, it is essential that the same library that allocates memory must free it. Thus ALLOC calls must be matched to ruby_xfree calls, which they were not. In addition, in one case Ruby was allocating memory to be freed by libxml. On Windows, that's a segmentation fault. On Linux it might fly, but still seems like a bad idea. * Fixed segmentation fault in xml reader expand (same xml tree freed twice) * Applied a number of patches from Tom Bagby, including fixes for xpath segmentation faults and fixes for various memory leaks * Cleaned up a number of compiler warnings * Renamed libxml_so.so to libxml_ruby.so (same for xslt). That wasn't actually my original intention, but um, it kind of sort of happened. It should not be noticeable from an end-user perspective. * Added rake files for building with MingW * Added rake files for packing gems. Note that I did this outside the existing rake tasks because I didn't see how they were actually building the gems. * Cleaned up the tests and added a few more based on bug reports from the Tracker and mailing list. * Cleaned out the patch queue and went through about 1/2 the bug list === 2007-11-16 "Dan Janowski" * Merged Dan's MEM2 branch to trunk. == 0.5.3 / === 2007-11-16 "Dan Janowski" * Merged Dan's MEM2 branch to trunk. == 0.5.2 / 2007-10-10 === 2007-10-10 "Dan Janowski" * (Dan, fill in the major points of the changes you made up to here -thanks) === 2007-01-14 "Laurent Sansonetti" * Added some preliminary RDoc comments for XML::Reader. === 2006-12-05 "Laurent Sansonetti" * Added XML::Reader, a set of bindings to the xmlTextReader API. == 0.3.8.4 / 2006-12-02 === 2006-04-15 "Ross Bamform" * Implemented SAX parser callback handling. === 2006-04-12 "Ross Bamford" * Integrated and tested community patches. * Defined XML::Node (hash) equality in terms of XML representation. === 2006-04-12 "Tim Yamin" * Fixed XML::Node#content inoperable bug (plasmaroo) [patch] * Fixed memory leak in same === 2006-04-12 "Mark Van Holstyn" * Added XML::Node::Set#first (mvette13) [patch] * Added XML::Node::Set#empty? * Fixed XML::Node::Set#to_a * Added XML::Node#find_first * Added XML::Node#remove! === 2006-03-27 "Ross Bamford" * Integrated contributed XML::Parser.register_error_handler patch (rosco) === 2006-02-27 "Ross Bamford" * Fixed all multiple symbol definitions for -fno-common. * Removed OSX -fno-common workaround. == 0.3.6 / 2006-02-23 === 2006-02-21 "Ross Bamford" * Patched extconf.rb with OSX -fno-common workaround * Added gem and packaging support to Rakefile * Moved version update to Rakefile * Removed legacy project utility scripts === 2005-02-19 "Ross Bamford" * Fixed doublefree bug in ruby_xml_attr. * Fixed small leak in parser === 2005-12-18 "Ross Bamford" * Updated for GCC 4.0 (community patches) * Fixed default validation bug * Refactored project, removed outdated files, cleaned up tests. * Added RDoc documentation across .c files. * Fixed up a few strings. === 2004-04-04 "Mangler Jurgen" * ruby_xml_node.cz: fixed ruby_xml_node_property_set. The ill-behaviour was, that there was added a second attribute of the same name, when you were setting the value of an already existing attribute. === 2004-03-17 "Lukas Svoboda" * ruby_xml_node.c: ruby_xml_node_to_s now returns XML subtree dump. === 2004-02-27 "Martin Povolny" * ruby_xml_node.c: added XML::Node.copy, this makes possible building of xml documents from nodes taken from other xml documents without making ruby SIGSEGV (see tests/copy_bug.rb). === 2004-02-26 "Martin Povolny" * ruby_xml_dtd.c, ruby_xml_dtd.h, ruby_xml_schema.c, ruby_xml_schema.h: more work on validation, now you can actually validate document using dtd or xml schema, also solved warning and error propagation (see tests/{dtd|schema}-test.rb). === 2003-12-30 "Martin Povolny" * ruby_xml_dtd.c, ruby_xml_dtd.h, ruby_xml_schema.c, ruby_xml_schema.h: prelimitary support for dtd and schema validation === 2003-09-15 "Martin Povolny" * ruby_xml_input_cbg.c, libxml.c: added class InputCallbacks to make possible registering custom input callbacks handlers (xmlRegisterInputCallbacks) written in ruby === 2003-08-01 "Martin Povolny" * ruby_xml_document.c: corrected argument handling in ruby_xml_document_find * ruby_xml_node.c: corrected argument handling in ruby_xml_node_find libxml-ruby-5.0.3/test/0000755000004100000410000000000014620142101014763 5ustar www-datawww-datalibxml-ruby-5.0.3/test/test_node_comment.rb0000644000004100000410000000154414620142101021022 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class NodeCommentTest < Minitest::Test def setup xp = LibXML::XML::Parser.string('') @doc = xp.parse assert_instance_of(LibXML::XML::Document, @doc) @root = @doc.root end def test_libxml_node_add_comment_01 @root << LibXML::XML::Node.new_comment('mycomment') assert_equal '', @root.to_s.gsub(/\n\s*/,'') end def test_libxml_node_add_comment_02 @root << LibXML::XML::Node.new_comment('mycomment') assert_equal 'comment', @root.child.node_type_name end def test_libxml_node_add_comment_03 @root << el = LibXML::XML::Node.new_comment('mycomment') el << "_this_is_added" assert_equal '', @root.to_s.gsub(/\n\s*/,'') end end libxml-ruby-5.0.3/test/test_node_pi.rb0000644000004100000410000000173214620142101017767 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class NodePiTest < Minitest::Test def setup xp = LibXML::XML::Parser.string('') @doc = xp.parse assert_instance_of(LibXML::XML::Document, @doc) @root = @doc.root end def test_libxml_node_add_pi_01 @root << LibXML::XML::Node.new_pi('mypi') assert_equal '', @root.to_s.gsub(/\n\s*/,'') end def test_libxml_node_add_pi_02 @root << LibXML::XML::Node.new_pi('mypi') assert_equal 'pi', @root.child.node_type_name end def test_libxml_node_add_pi_03 @root << el = LibXML::XML::Node.new_pi('mypi') el << "_this_is_added" assert_equal '', @root.to_s.gsub(/\n\s*/,'') end def test_libxml_node_add_pi_04 @root << LibXML::XML::Node.new_pi('mypi','mycontent') assert_equal '', @root.to_s.gsub(/\n\s*/,'') end end libxml-ruby-5.0.3/test/test_xpath_context.rb0000644000004100000410000000522614620142101021244 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' require "tempfile" class TestXPathContext < Minitest::Test SOAP_PREFIX = 'soap' SOAP_URI = 'http://schemas.xmlsoap.org/soap/envelope/' NS0_PREFIX = 'ns0' NS0_URI = 'http://services.somewhere.com' def setup doc = LibXML::XML::Document.file(File.join(File.dirname(__FILE__), 'model/soap.xml')) @context = LibXML::XML::XPath::Context.new(doc) end def teardown() @context = nil end def test_no_ns error = assert_raises(LibXML::XML::Error) do @context.find('/soap:Envelope') end assert_equal("Error: Undefined namespace prefix.", error.to_s) end def test_ns_register @context.register_namespace(SOAP_PREFIX, SOAP_URI) @context.register_namespace(NS0_PREFIX, NS0_URI) nodes = @context.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse') assert_equal(1, nodes.length) end def test_ns_register_string @context.register_namespaces("#{SOAP_PREFIX}:#{SOAP_URI}") @context.register_namespaces("#{NS0_PREFIX}:#{NS0_URI}") nodes = @context.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse') assert_equal(1, nodes.length) end def test_ns_register_array @context.register_namespaces(["#{SOAP_PREFIX}:#{SOAP_URI}", "#{NS0_PREFIX}:#{NS0_URI}"]) nodes = @context.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse') assert_equal(1, nodes.length) end def test_ns_register_hash @context.register_namespaces(SOAP_PREFIX => SOAP_URI, NS0_PREFIX => NS0_URI) nodes = @context.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse') assert_equal(1, nodes.length) end def test_ns_register_node @context.register_namespaces_from_node(@context.doc.root) nodes = @context.find('/soap:Envelope') assert_equal(1, nodes.length) end def test_node @context.register_namespaces_from_node(@context.doc.root) nodes = @context.find('soap:Body') assert_equal(0, nodes.length) @context.node = @context.doc.root.child.next nodes = @context.find('soap:Body') assert_equal(0, nodes.length) end def test_cache @context.enable_cache @context.enable_cache(10) @context.disable_cache end def test_require_doc doc = LibXML::XML::Document.file(File.join(File.dirname(__FILE__), 'model/soap.xml')) error = assert_raises(TypeError) do @context = LibXML::XML::XPath::Context.new(doc.root) end assert_equal("Supplied argument must be a document or node.", error.to_s) end endlibxml-ruby-5.0.3/test/test_namespace.rb0000644000004100000410000000330614620142101020305 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestNS < Minitest::Test def setup file = File.join(File.dirname(__FILE__), 'model/soap.xml') @doc = LibXML::XML::Document.file(file) end def teardown @doc = nil end def test_create_ns node = LibXML::XML::Node.new('foo') ns = LibXML::XML::Namespace.new(node, 'my_namepace', 'http://www.mynamespace.com') assert_equal(ns.prefix, 'my_namepace') assert_equal(ns.href, 'http://www.mynamespace.com') end def test_create_default_ns node = LibXML::XML::Node.new('foo') ns = LibXML::XML::Namespace.new(node, nil, 'http://www.mynamespace.com') assert_nil(ns.prefix) assert_equal(ns.href, 'http://www.mynamespace.com') end def test_create_unbound_ns error = assert_raises(TypeError) do LibXML::XML::Namespace.new(nil, 'my_namepace', 'http://www.mynamespace.com') end assert_equal('wrong argument type nil (expected Data)', error.to_s) end def test_duplicate_ns node = LibXML::XML::Node.new('foo') LibXML::XML::Namespace.new(node, 'myname', 'http://www.mynamespace.com') LibXML::XML::Namespace.new(node, 'myname', 'http://www.mynamespace.com') end def test_eql node = LibXML::XML::Node.new('Envelope') assert(node.namespaces.namespace.eql?(node.namespaces.namespace)) end def test_equal node1 = LibXML::XML::Node.new('Envelope') ns1 = LibXML::XML::Namespace.new(node1, 'soap', 'http://schemas.xmlsoap.org/soap/envelope/') node2 = LibXML::XML::Node.new('Envelope') ns2 = LibXML::XML::Namespace.new(node2, 'soap', 'http://schemas.xmlsoap.org/soap/envelope/') assert(ns1 == ns2) end end libxml-ruby-5.0.3/test/test_deprecated_require.rb0000644000004100000410000000056414620142101022210 0ustar www-datawww-data# encoding: UTF-8 require 'xml/libxml' class TestDeprecatedRequire < Minitest::Test def test_basic xp = LibXML::XML::Parser.string('onetwo') assert_instance_of(LibXML::XML::Parser, xp) @doc = xp.parse assert_instance_of(LibXML::XML::Document, @doc) end end libxml-ruby-5.0.3/test/test_node_xlink.rb0000644000004100000410000000143514620142101020504 0ustar www-datawww-data# encoding: UTF-8 # $Id$ require_relative './test_helper' class TC_XML_Node_XLink < Minitest::Test def setup() xp = LibXML::XML::Parser.string('one') doc = xp.parse assert_instance_of(LibXML::XML::Document, doc) @root = doc.root assert_instance_of(LibXML::XML::Node, @root) end def teardown() @root = nil end def test_xml_node_xlink() for elem in @root.find('fixnum') assert_instance_of(LibXML::XML::Node, elem) assert_instance_of(TrueClass, elem.xlink?) assert_equal("simple", elem.xlink_type_name) assert_equal(LibXML::XML::Node::XLINK_TYPE_SIMPLE, elem.xlink_type) end end end libxml-ruby-5.0.3/test/test_dtd.rb0000644000004100000410000001065014620142101017124 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestDtd < Minitest::Test def setup xp = LibXML::XML::Parser.string(<<-EOS) Colorado Lots of nice mountains EOS @doc = xp.parse end def teardown @doc = nil end def dtd LibXML::XML::Dtd.new(<<-EOS) EOS end def test_internal_subset xhtml_dtd = LibXML::XML::Dtd.new("-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", nil, nil, true) assert xhtml_dtd.name.nil? assert_equal "-//W3C//DTD XHTML 1.0 Transitional//EN", xhtml_dtd.external_id assert_equal "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", xhtml_dtd.uri assert_equal "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", xhtml_dtd.system_id xhtml_dtd = LibXML::XML::Dtd.new("-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", "xhtml1", nil, true) assert_equal "xhtml1", xhtml_dtd.name assert_equal "-//W3C//DTD XHTML 1.0 Transitional//EN", xhtml_dtd.external_id assert_equal "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", xhtml_dtd.uri assert_equal "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", xhtml_dtd.system_id end def test_external_subset xhtml_dtd = LibXML::XML::Dtd.new("-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", nil) assert xhtml_dtd.name.nil? assert_equal "-//W3C//DTD XHTML 1.0 Transitional//EN", xhtml_dtd.external_id assert_equal "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", xhtml_dtd.uri assert_equal "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", xhtml_dtd.system_id xhtml_dtd = LibXML::XML::Dtd.new("-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", "xhtml1") assert_equal "xhtml1", xhtml_dtd.name assert_equal "-//W3C//DTD XHTML 1.0 Transitional//EN", xhtml_dtd.external_id assert_equal "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", xhtml_dtd.uri assert_equal "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", xhtml_dtd.system_id end def test_valid assert(@doc.validate(dtd)) end def test_node_type assert_equal(LibXML::XML::Node::DTD_NODE, dtd.node_type) end def test_invalid new_node = LibXML::XML::Node.new('invalid', 'this will mess up validation') @doc.root << new_node error = assert_raises(LibXML::XML::Error) do @doc.validate(dtd) end # Check the error worked refute_nil(error) assert_kind_of(LibXML::XML::Error, error) assert_equal("Error: No declaration for element invalid.", error.message) assert_equal(LibXML::XML::Error::VALID, error.domain) assert_equal(LibXML::XML::Error::DTD_UNKNOWN_ELEM, error.code) assert_equal(LibXML::XML::Error::ERROR, error.level) assert_nil(error.file) assert_nil(error.line) assert_equal('invalid', error.str1) # Different answers across operating systems # assert_nil(error.str2) assert_nil(error.str3) assert_equal(0, error.int1) assert_equal(0, error.int2) refute_nil(error.node) assert_equal('invalid', error.node.name) end def test_external_dtd xml = <<-EOS T1 EOS errors = Array.new LibXML::XML::Error.set_handler do |error| errors << error end LibXML::XML::Parser.string(xml).parse assert_equal(0, errors.length) errors.clear LibXML::XML::Parser.string(xml, options: LibXML::XML::Parser::Options::DTDLOAD).parse assert_equal(1, errors.length) assert_equal("Warning: failed to load external entity \"test.dtd\" at :1.", errors[0].to_s) errors = Array.new LibXML::XML::Parser.string(xml, :options => LibXML::XML::Parser::Options::DTDLOAD).parse assert_equal(1, errors.length) assert_equal("Warning: failed to load external entity \"test.dtd\" at :1.", errors[0].to_s) ensure LibXML::XML::Error.reset_handler end end libxml-ruby-5.0.3/test/test_node_edit.rb0000644000004100000410000001117014620142101020301 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestNodeEdit < Minitest::Test def setup xp = LibXML::XML::Parser.string('onetwothree') @doc = xp.parse end def teardown @doc = nil end def first_node @doc.root.child end def second_node first_node.next end def third_node second_node.next end def test_add_next_01 first_node.next = LibXML::XML::Node.new('num', 'one-and-a-half') assert_equal('oneone-and-a-halftwothree', @doc.root.to_s.gsub(/\n\s*/,'')) end def test_add_next_02 second_node.next = LibXML::XML::Node.new('num', 'two-and-a-half') assert_equal('onetwotwo-and-a-halfthree', @doc.root.to_s.gsub(/\n\s*/,'')) end def test_add_next_03 third_node.next = LibXML::XML::Node.new('num', 'four') assert_equal 'onetwothreefour', @doc.root.to_s.gsub(/\n\s*/,'') end def test_add_prev_01 first_node.prev = LibXML::XML::Node.new('num', 'half') assert_equal 'halfonetwothree', @doc.root.to_s.gsub(/\n\s*/,'') end def test_add_prev_02 second_node.prev = LibXML::XML::Node.new('num', 'one-and-a-half') assert_equal 'oneone-and-a-halftwothree', @doc.root.to_s.gsub(/\n\s*/,'') end def test_add_prev_03 third_node.prev = LibXML::XML::Node.new('num', 'two-and-a-half') assert_equal 'onetwotwo-and-a-halfthree', @doc.root.to_s.gsub(/\n\s*/,'') end def test_remove_node first_node.remove! assert_equal('twothree', @doc.root.to_s.gsub(/\n\s*/,'')) end def test_remove_node_gc xp = LibXML::XML::Parser.string('onetwothree') doc = xp.parse doc.root.child.remove! GC.start refute_nil(doc) end def test_remove_node_iteration nodes = Array.new @doc.root.each_element do |node| if node.name == 'num' nodes << node node.remove! end end assert_equal(3, nodes.length) end def test_reuse_removed_node # Remove the node node = @doc.root.first.remove! refute_nil(node) # Add it to the end of the document @doc.root.last.next = node assert_equal('twothreeone', @doc.root.to_s.gsub(/\n\s*/,'')) end def test_append_existing_node doc = LibXML::XML::Parser.string('abfirstsecondcd').parse node1 = doc.find_first('//two') doc.root << node1 assert_equal('abfirstcdsecond', doc.root.to_s) end def test_wrong_doc doc1 = LibXML::XML::Parser.string('').parse doc2 = LibXML::XML::Parser.string('').parse node = doc1.root.child error = assert_raises(LibXML::XML::Error) do doc2.root << node end GC.start assert_equal(' Nodes belong to different documents. You must first import the node by calling LibXML::XML::Document.import.', error.to_s) end # This test is to verify that an earlier reported bug has been fixed def test_merge documents = [] # Read in 500 documents 500.times do documents << LibXML::XML::Parser.string(File.read(File.join(File.dirname(__FILE__), 'model', 'merge_bug_data.xml'))).parse end master_doc = documents.shift documents.each do |child_doc| master_body = master_doc.find("//body").first child_body = child_doc.find("//body").first child_element = child_body.detect do |node| node.element? end master_body << child_element.copy(true) end end def test_append_chain node = LibXML::XML::Node.new('foo') << LibXML::XML::Node.new('bar') << "bars contents" assert_equal('bars contents', node.to_s) end def test_set_base @doc.root.base_uri = 'http://www.rubynet.org/' assert_equal("\n one\n two\n three\n", @doc.root.to_s) end end libxml-ruby-5.0.3/test/test_html_parser_context.rb0000644000004100000410000000113414620142101022432 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestHtmlParserContext < Minitest::Test def test_default_options context = LibXML::XML::HTMLParser::Context.new assert_equal(0, context.options) end def test_no_options context = LibXML::XML::HTMLParser::Context.new context.options = 0 assert_equal(0, context.options) end def test_options context = LibXML::XML::HTMLParser::Context.new context.options = LibXML::XML::HTMLParser::Options::NOERROR assert_equal(LibXML::XML::HTMLParser::Options::NOERROR, context.options) end endlibxml-ruby-5.0.3/test/test_document.rb0000644000004100000410000001042114620142101020163 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestDocument < Minitest::Test def setup xp = LibXML::XML::Parser.string('onetwo') assert_instance_of(LibXML::XML::Parser, xp) @doc = xp.parse assert_instance_of(LibXML::XML::Document, @doc) end def teardown @doc = nil end def test_klass assert_instance_of(LibXML::XML::Document, @doc) end def test_context context = @doc.context assert_instance_of(LibXML::XML::XPath::Context, context) end def test_find set = @doc.find('/ruby_array/fixnum') assert_instance_of(LibXML::XML::XPath::Object, set) assert_raises(NoMethodError) { set.xpath } end def test_compression if LibXML::XML.enabled_zlib? 0.upto(9) do |i| assert_equal(i, @doc.compression = i) assert_equal(i, @doc.compression) end 9.downto(0) do |i| assert_equal(i, @doc.compression = i) assert_equal(i, @doc.compression) end 10.upto(20) do |i| # assert_equal(9, @doc.compression = i) assert_equal(i, @doc.compression = i) # This works around a bug in Ruby 1.8 assert_equal(9, @doc.compression) end -1.downto(-10) do |i| # assert_equal(0, @doc.compression = i) assert_equal(i, @doc.compression = i) # FIXME This bug should get fixed ASAP assert_equal(0, @doc.compression) end end end def test_version assert_equal('1.0', @doc.version) doc = LibXML::XML::Document.new('6.9') assert_equal('6.9', doc.version) end def test_write_root @doc.root = LibXML::XML::Node.new('rubynet') assert_instance_of(LibXML::XML::Node, @doc.root) assert_instance_of(LibXML::XML::Document, @doc.root.doc) assert_equal("\n\n", @doc.to_s(:indent => false)) end def test_doc_node_type assert_equal(LibXML::XML::Node::DOCUMENT_NODE, LibXML::XML::Document.new.node_type) end def test_doc_node_type_name assert_equal('document_xml', LibXML::XML::Document.new.node_type_name) end def test_xhtml doc = LibXML::XML::Document.new assert(!doc.xhtml?) LibXML::XML::Dtd.new("-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", nil, doc, true) assert(doc.xhtml?) end def test_document_root doc1 = LibXML::XML::Document.string("") doc2 = LibXML::XML::Document.string("") error = assert_raises(LibXML::XML::Error) do doc1.root = doc2.root end assert_equal(" Nodes belong to different documents. You must first import the node by calling LibXML::XML::Document.import.", error.to_s) doc2.root << doc2.import(doc1.root) assert_equal('', doc1.root.to_s) assert_equal('', doc2.root.to_s(:indent => false)) assert(!doc1.root.equal?(doc2.root)) assert(doc1.root.doc != doc2.root.doc) end def test_import_node doc1 = LibXML::XML::Parser.string('').parse doc2 = LibXML::XML::Parser.string('').parse node = doc1.root.child error = assert_raises(LibXML::XML::Error) do doc2.root << node end assert_equal(" Nodes belong to different documents. You must first import the node by calling LibXML::XML::Document.import.", error.to_s) doc2.root << doc2.import(node) assert_equal("", doc2.root.to_s(:indent => false)) end def test_nonet xml_string = 'onetwo' xml = LibXML::XML::Document.string(xml_string, options: LibXML::XML::Parser::Options::NONET) file = File.join(File.dirname(__FILE__), 'model/atom.xml') schema_document = LibXML::XML::Document.file(file, options: LibXML::XML::Parser::Options::NONET) end def test_io File.open(File.join(File.dirname(__FILE__), 'model/rubynet.xml')) do |io| doc = LibXML::XML::Document.io(io) assert_instance_of(LibXML::XML::Document, doc) end end end libxml-ruby-5.0.3/test/test_reader.rb0000644000004100000410000003241014620142101017611 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' require 'stringio' class TestReader < Minitest::Test XML_FILE = File.join(File.dirname(__FILE__), 'model/atom.xml') def verify_simple(reader) node_types = [] # Read each node 26.times do assert(reader.read) node_types << reader.node_type end # There are no more nodes assert(!reader.read) # Check what was read expected = [LibXML::XML::Reader::TYPE_PROCESSING_INSTRUCTION, LibXML::XML::Reader::TYPE_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_COMMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_ELEMENT, LibXML::XML::Reader::TYPE_CDATA, LibXML::XML::Reader::TYPE_END_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_ELEMENT, LibXML::XML::Reader::TYPE_TEXT, LibXML::XML::Reader::TYPE_END_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_END_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_END_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_END_ELEMENT, LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE, LibXML::XML::Reader::TYPE_END_ELEMENT] assert_equal(expected, node_types) end def test_document reader = LibXML::XML::Reader.document(LibXML::XML::Document.file(XML_FILE)) verify_simple(reader) end def test_file reader = LibXML::XML::Reader.file(XML_FILE) verify_simple(reader) end def test_invalid_file error = assert_raises(Errno::ENOENT) do LibXML::XML::Reader.file('/does/not/exist') end assert_equal("No such file or directory - /does/not/exist", error.message) end def test_string reader = LibXML::XML::Reader.string(File.read(XML_FILE)) verify_simple(reader) end def test_io File.open(XML_FILE, 'rb') do |io| reader = LibXML::XML::Reader.io(io) verify_simple(reader) end end def test_io_gc # Test that the reader keeps a reference # to the io object file = File.open(XML_FILE, 'rb') reader = LibXML::XML::Reader.io(file) file = nil GC.start assert(reader.read) end def test_string_io data = File.read(XML_FILE) string_io = StringIO.new(data) reader = LibXML::XML::Reader.io(string_io) verify_simple(reader) end def test_error reader = LibXML::XML::Reader.string('") assert(parser.read) assert_equal('foo', parser.name) assert_equal('1', parser['x']) assert_equal('1', parser[0]) assert_equal('2', parser['y']) assert_equal('2', parser[1]) assert_nil(parser['z']) assert_nil(parser[2]) end def test_move_attr reader = LibXML::XML::Reader.string('') assert(reader.read) # assert(reader.read) # assert(reader.move_to_attribute_no(1)) assert_equal(reader.value, 'def') assert(reader.move_to_attribute_ns('id', 'http://www.w3.org/XML/1998/namespace')) assert_equal(reader.value, 'abc') assert(reader.move_to_attribute('bar')) assert_equal(reader.value, 'jkl') # 1 in case of success, -1 in case of error, 0 if not found assert_equal(reader.move_to_attribute_no(12), 0) assert_equal(reader.move_to_attribute('baz'), 0) assert_equal(reader.move_to_attribute_ns('baz', 'http://ruby/namespace'), 0) end def test_get_attr reader = LibXML::XML::Reader.string('') assert(reader.read) # assert(reader.read) # assert_equal(reader.get_attribute_no(1), 'def') assert_equal(reader.get_attribute_ns('id', 'http://www.w3.org/XML/1998/namespace'), 'abc') assert_equal(reader.get_attribute('bar'), 'jkl') assert_nil(reader.get_attribute_no(12)) assert_nil(reader.get_attribute('baz')) assert_nil(reader.get_attribute_ns('baz', 'http://ruby/namespace')) end def test_value parser = LibXML::XML::Reader.string("123") assert(parser.read) assert_equal('foo', parser.name) assert_nil(parser.value) 3.times do |i| assert(parser.read) assert_equal(LibXML::XML::Reader::TYPE_ELEMENT, parser.node_type) assert_equal('bar', parser.name) assert(parser.read) assert_equal(LibXML::XML::Reader::TYPE_TEXT, parser.node_type) assert_equal((i + 1).to_s, parser.value) assert(parser.read) assert_equal(LibXML::XML::Reader::TYPE_END_ELEMENT, parser.node_type) end end def test_expand reader = LibXML::XML::Reader.file(XML_FILE) reader.read.to_s reader.read # Read a node node = reader.expand refute_nil(node.doc) assert_equal('feed', node.name) assert_equal(::Encoding::UTF_8, node.name.encoding) if defined?(::Encoding) end def test_expand_find reader = LibXML::XML::Reader.file(XML_FILE) reader.read.to_s reader.read # Read first node which node = reader.expand assert_equal('feed', node.name) # We need to create document to use xpath reader.doc # Search for entries entries = node.find('atom:entry', 'atom:http://www.w3.org/2005/Atom') assert_equal(1, entries.length) end def test_expand_invalid reader = LibXML::XML::Reader.file(XML_FILE) # Expand a node before one has been read node = reader.expand assert_nil(node) end def test_expand_should_be_invalid reader = LibXML::XML::Reader.file(XML_FILE) # Read a couple of nodes reader.read reader.read # Expand the node node = reader.expand assert_equal('feed', node.name) # Read another node, this makes the last node invalid reader.next # The previous node is now invalid - this should be an error but isn't assert_equal('feed', node.name) end def test_expand_incorrectly_use_returned_node file = File.join(File.dirname(__FILE__), 'model/cwm_1_0.xml') reader = LibXML::XML::Reader.file(file) nodes = Array.new while reader.read node = reader.expand refute_nil(node) refute_nil(node.doc) # NOTE - DO NOT do this in real code, these nodes are invalid after the next read. This *will* cause # a segmentation fault next time the garbage collector runs. The reason is the parent node will be # called in the mark phase, but its underlying xml node will be gone. Same goes for calling children, # attributes, etc. You must let go of the expanded node *before* calling xml reader again and # call the garbage collector to be safe. #refute_nil(node.parent) nodes << node end assert(true) end def test_mode reader = LibXML::XML::Reader.string('') assert_equal(LibXML::XML::Reader::MODE_INITIAL, reader.read_state) reader.read assert_equal(LibXML::XML::Reader::MODE_EOF, reader.read_state) end def test_bytes_consumed ending_are_rn = File.binread(XML_FILE).include? "\r\n" reader = LibXML::XML::Reader.file(XML_FILE) reader.read assert_equal(ending_are_rn ? 428 : 416, reader.byte_consumed) end def test_node reader = LibXML::XML::Reader.file(XML_FILE) # first try to get a node assert_nil(reader.node) reader.read assert_instance_of(LibXML::XML::Node, reader.node) end def test_base_uri # UTF8: # ö - c3 b6 in hex, \303\266 in octal # ü - c3 bc in hex, \303\274 in octal xml = "\n An American heavy metal band formed in Los Angeles, California in 1981.\n British heavy metal band formed in 1975.\n" reader = LibXML::XML::Reader.string(xml, :base_uri => "http://libxml.rubyforge.org") reader.read assert_equal(reader.base_uri, "http://libxml.rubyforge.org") assert_equal(::Encoding::UTF_8, reader.base_uri.encoding) if defined?(::Encoding) end def test_options xml = <<-EOS ]> &foo; EOS # Parse normally reader = LibXML::XML::Reader.string(xml) reader.read # foo reader.read # test reader.read # text reader.read # cdata reader.read # cdata-section assert_equal(LibXML::XML::Node::CDATA_SECTION_NODE, reader.node_type) # Convert cdata section to text reader = LibXML::XML::Reader.string(xml, :options => LibXML::XML::Parser::Options::NOCDATA) reader.read # foo reader.read # test reader.read # text reader.read # cdata reader.read # cdata-section assert_equal(LibXML::XML::Node::TEXT_NODE, reader.node_type) end def test_encoding # ISO_8859_1: # ö - f6 in hex, \366 in octal # ü - fc in hex, \374 in octal xml = "\n An American heavy metal band formed in Los Angeles, California in 1981.\n British heavy metal band formed in 1975.\n" reader = LibXML::XML::Reader.string(xml, :encoding => LibXML::XML::Encoding::ISO_8859_1) reader.read assert_equal(Encoding::ISO8859_1, reader.read_outer_xml.encoding) assert_equal(Encoding::ISO8859_1, reader.read_inner_xml.encoding) assert_equal(Encoding::ISO8859_1, reader.read_string.encoding) assert_equal("\n An American heavy metal band formed in Los Angeles, California in 1981.\n British heavy metal band formed in 1975.\n".force_encoding(Encoding::ISO8859_1), reader.read_outer_xml) assert_equal("\n An American heavy metal band formed in Los Angeles, California in 1981.\n British heavy metal band formed in 1975.\n".force_encoding(Encoding::ISO8859_1), reader.read_inner_xml) assert_equal("\n An American heavy metal band formed in Los Angeles, California in 1981.\n British heavy metal band formed in 1975.\n".force_encoding(Encoding::ISO8859_1), reader.read_string) end def test_invalid_encoding # ISO_8859_1: # ö - f6 in hex, \366 in octal # ü - fc in hex, \374 in octal xml = "\n An American heavy metal band formed in Los Angeles, California in 1981.\n British heavy metal band formed in 1975.\n" reader = LibXML::XML::Reader.string(xml) error = assert_raises(LibXML::XML::Error) do reader.read end assert_equal("Fatal error: Input is not proper UTF-8, indicate encoding !\nBytes: 0xF6 0x74 0x6C 0x65 at :2.", error.to_s) end def test_file_encoding reader = LibXML::XML::Reader.file(XML_FILE) reader.read assert_equal(LibXML::XML::Encoding::UTF_8, reader.encoding) assert_equal(Encoding::UTF_8, reader.value.encoding) end def test_string_encoding # ISO_8859_1: # ö - f6 in hex, \366 in octal # ü - fc in hex, \374 in octal xml = "\n An American heavy metal band formed in Los Angeles, California in 1981.\n British heavy metal band formed in 1975.\n" reader = LibXML::XML::Reader.string(xml, :encoding => LibXML::XML::Encoding::ISO_8859_1) reader.read encoding = windows? ? LibXML::XML::Encoding::ISO_8859_1 : LibXML::XML::Encoding::NONE assert_equal(reader.encoding, encoding) end end libxml-ruby-5.0.3/test/test_node_text.rb0000644000004100000410000000403014620142101020335 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestTextNode < Minitest::Test def test_content node = LibXML::XML::Node.new_text('testdata') assert_instance_of(LibXML::XML::Node, node) assert_equal('testdata', node.content) end def test_invalid_content error = assert_raises(TypeError) do LibXML::XML::Node.new_text(nil) end assert_equal('wrong argument type nil (expected String)', error.to_s) end # We use the same facility that libXSLT does here to disable output escaping. # This lets you specify that the node's content should be rendered unaltered # whenever it is being output. This is useful for things like libxml-ruby-5.0.3/test/model/atom.xml0000644000004100000410000000065414620142101017552 0ustar www-datawww-data <![CDATA[<<strong>>]]> hi there libxml-ruby-5.0.3/test/model/rubynet_project0000644000004100000410000000007114620142101021222 0ustar www-datawww-dataThis is some text to include in an xml file via XInclude.libxml-ruby-5.0.3/test/model/shiporder.rng0000644000004100000410000000372514620142101020601 0ustar www-datawww-data libxml-ruby-5.0.3/test/model/bands.iso-8859-1.xml0000644000004100000410000000046314620142101021241 0ustar www-datawww-data Mötley Crüe is an American heavy metal band formed in Los Angeles, California in 1981. Iron Maiden is a British heavy metal band formed in 1975. libxml-ruby-5.0.3/test/model/shiporder.rnc0000644000004100000410000000166414620142101020575 0ustar www-datawww-data# # relax ng schema in compact syntax; this cannot be used within libxml but # was used to write the schema as compact syntax makes it easier to handle. # relax ng schema in xml syntax was created using trang. # namespace xsi = "http://www.w3.org/2001/XMLSchema-instance" start = shiporderType shiporderType = element shiporder { attribute orderid { text }, attribute xsi:noNamespaceSchemaLocation { text }, orderperson, shipto, item* } orderperson = element orderperson { text } shipto = element shipto { name, address, city, country } name = element name { text } address = element address { text } city = element city { text } country = element country { text } item = element item { title, note?, quantity, price } title = element title { text } note = element note { text } quantity = element quantity { text } price = element price { text } libxml-ruby-5.0.3/test/model/cwm_1_0.xml0000644000004100000410000371670714620142101020057 0ustar www-datawww-data Unisys.JCR.1 1.3.2 The Core metamodel depends on no other packages. The ObjectModel Core metamodel contains basic metamodel classes and associations used by all other CWM metamodel packages, including other ObjectModel packages OCL Representation of Core Constraints Operations The operation allFeatures results in a Set containing all Features of the Classifier itself and all its inherited Features. allFeatures : Set(Feature); allFeatures = self.feature->union(self.parent.oclAsType(Classifier).allFeatures) The operation allAttributes results in a Set containing all Attributes of the Classifier itself and all its inherited Attributes. allAttributes : set(Attribute); allAttributes = self.allFeatures->select(f | f.oclIsKindOf(Attribute)) The operation specification yields the set of Classifiers that the current Classifier realizes. specification: Set(Classifier) specification = self.clientDependency-> select(d | d.stereotype.name = "realization" and d.supplier.oclIsKindOf(Classifier)).supplier.oclAsType(Classifier) The operation parent returns a Set containing all direct parents of a Classifier. parent : Set(Classifier); parent = self.generalization.parent The operation allParents returns a Set containing all the Classifiers inherited by this Classifier (the transitive closure), excluding the Classifier itself. allParents : Set(Classifier); allParents = self.parent->union(self.parent.allParents) The operation allContents returns a Set containing all ModelElements contained in the Classifier together with the contents inherited from its parents. allContents : Set(ModelElement); allContents = self.contents->union(self.parent.allContents-> select(e | e.elementOwnership.visibility = #public or e.elementOwnership.visibility = #protected)) The operation supplier results in a Set containing all direct suppliers of the ModelElement. supplier : Set(ModelElement); supplier = self.clientDependency.supplier The operation allSuppliers results in a Set containing all the ModelElements that are suppliers of this ModelElement, including the suppliers of these Model Elements. This is the transitive closure. allSuppliers : Set(ModelElement); allSuppliers = self.supplier->union(self.supplier.allSuppliers) The operation contents results in a Set containing all ModelElements contained by the Namespace. contents : Set(ModelElement) contents = self.ownedElement -> union(self.namespace.contents) The operation allContents results in a Set containing all ModelElements contained by the Namespace. allContents : Set(ModelElement); allContents = self.contents The operation allVisibleElements results in a Set containing all ModelElements visible outside of the Namespace. allVisibleElements : Set(ModelElement) allVisibleElements = self.allContents -> select(e | e.elementOwnership.visibility = #public) The operation allSurroundingNamespaces results in a Set containing all surrounding Namespaces. allSurroundingNamespaces : Set(Namespace) allSurroundingNamespaces = self.namespace->union(self.namespace.allSurroundingNamespaces) The operation contents results in a Set containing the ModelElements owned by or imported by the Package. contents : Set(ModelElement) contents = self.ownedElement->union(self.importedElement) The operation allImportedElements results in a Set containing the ModelElements imported by the Package. allImportedElements : Set(ModelElement) allImportedElements = self.importedElement The operation allContents results in a Set containing the ModelElements owned by or imported by the Package. allContents : Set(ModelElement) allContents = self.contents Constraints [C-3-1] A Constraint cannot be applied to itself. context Constraint inv: not self.constrainedElement->includes (self) [C-3-2] A DataType cannot contain any other ModelElements. context DataType inv: self.ownedElement->isEmpty [C-3-3] Tags associated with a model element (directly via a property list or indirectly via a stereotype) must not clash with any meta attributes associated with the model element. context ModelElement inv: -- cannot be specified with OCL org.omg.cwm.objectmodel CWM CoreModule org.omg.java.cwm.objectmodel An element is an atomic constituent of a model. In the metamodel, an Element is the top metaclass in the metaclass hierarchy. Element is an abstract metaclass. A model element is an element that is an abstraction drawn from the system being modeled. In the metamodel, a ModelElement is a named entity in a Model. It is the base for all modeling metaclasses in the CWM. All other modeling metaclasses are either direct or indirect subclasses of ModelElement. true A namespace is a part of a model that contains a set of ModelElements each of whose names designates a unique element within the namespace. In the metamodel, a Namespace is a ModelElement that can own other ModelElements, such as Classifiers. The name of each owned ModelElement must be unique within the Namespace. Moreover, each contained ModelElement is owned by at most one Namespace. The concrete subclasses of Namespace may have additional constraints on which kind of elements may be contained. Namespace is an abstract metaclass. Note that explicit parts of a model element, such as the features of a Classifier, are not modeled as owned elements in a namespace. A namespace is used for unstructured contents such as the contents of a package, or a class declared inside the scope of another class. A classifier is an element that describes structural and behavioral features; it comes in several specific forms, including class, data type, interface, component, and others that are defined in other metamodel packages. Classifier is often used as a type. In the metamodel, a Classifier may declare a collection of Features, such as Attributes, Operations and Methods. It has a name, which is unique in the Namespace enclosing the Classifier. Classifier is an abstract metaclass. Classifier is a child of Namespace. As a Namespace, a Classifier may declare other Classifiers nested in its scope. Nested Classifiers may be accessed by other Classifiers only if the nested Classifiers have adequate visibility. There are no data value or state consequences of nested Classifiers, i.e., it is not an aggregation or composition. A class is a description of a set of objects that share the same attributes, operations, methods, relationships, and semantics. A class may use a set of interfaces to specify collections of operations it provides to its environment. In the metamodel, a Class describes a set of objects sharing a collection of Features that are common to the set of objects. The purpose of a Class is to declare a collection of Features that fully describe the structure and behavior of objects. Some Classes may not be directly instantiated. These Classes are said to be abstract and exist only for other Classes to inherit and reuse the Features declared by them. No object may be a direct instance of an abstract Class, although an object may be an indirect instance of one through a subclass that is non-abstract. A Class acts as the namespace for various kinds of contained elements defined within its scope, including classes, interfaces and associations (note that this is purely a scoping construction and does not imply anything about aggregation). The contained classes can be used as ordinary classes in the container class. If a class inherits another class, the contents of the ancestor are available to its descendents if the visibility of an element is public or protected; however, if the visibility is private, then the element is not visible and therefore not available in the descendant. A data type is a type whose values have no identity (i.e., they are pure values). Data types include primitive built-in types (such as integer and string) as well as definable enumeration types. In the metamodel, a DataType defines a special kind of Classifier in which operations are all pure functions (i.e., they can return data values but they cannot change data values, because they have no identity). For example, an "add" operation on a number with another number as an argument yields a third number as a result; the target and argument are unchanged. A DataType is a special kind of Classifier whose instances are primitive values, not objects. For example, integers and strings are usually treated as primitive values. A primitive value does not have an identity, so two occurrences of the same value cannot be differentiated. Usually, DataTypes are used for specification of the type of an attribute or parameter. A package is a grouping of model elements. In the metamodel, Package is a subclass of Namespace. A Package contains ModelElements such as Packages and Classifiers. A Package may also contain Constraints and Dependencies between ModelElements of the Package. The purpose of the package construct is to provide a general grouping mechanism. In fact, its only semantics is to define a namespace for its contents. The package construct can be used for organizing elements for any purpose; the criteria to use for grouping elements together into one package are not defined. A package owns a set of model elements, with the implication that if the package is removed from the model, so are the elements owned by the package. Elements with names, such as classifiers, that are owned by the same package must have unique names within the package, although elements in different packages may have the same name. There may be relationships between elements contained in the same package, and between an element in one package and an element in a surrounding package at any level. In other words, elements “see” all the way out through nested levels of packages. Elements in peer packages, however, are encapsulated and are not a priori visible to each other. The same goes for elements in contained packages, i.e. packages do not see "inwards". Elements owned by a Package can be made available to other Packages by importing them. Although any ModelElement may be imported by a Package, imported ModelElements are typically other Packages. When an element is imported by a package it extends the namespace of that package. Thus the elements available in a Package consists of its owned and imported ModelElements. A subsystem is a grouping of model elements that represents a behavioral unit in a physical system. A subsystem offers interfaces and has operations. In the metamodel, Subsystem is a subclass of both Package and Classifier. As such it may have a set of Features. The purpose of the subsystem construct is to provide a grouping mechanism for specifying a behavioral unit of a physical system. Apart from defining a namespace for its contents, a subsystem serves as a specification unit for the behavior of its contained model elements. The contents of a subsystem is defined in the same way as for a package, thus it consists of owned elements and imported elements, with unique names within the subsystem. A model captures a view of a physical system. It is an abstraction of the physical system, with a certain purpose. The model completely describes those aspects of the physical system that are relevant to the purpose of the model, at the appropriate level of detail. In the metamodel, Model is a subclass of Package. It contains a containment hierarchy of ModelElements that together describe the physical system. A Model also contains a set of ModelElements that represents the environment of the system. Different Models can be defined for the same physical system, where each model represents a view of the physical system defined by its purpose and abstraction level, e.g. an analysis model, a design model, an implementation model. Typically different models are complementary and defined from the perspectives (viewpoints) of different system stakeholders. A feature is a property, like attribute or operation, which is encapsulated within a Classifier. In the metamodel, a Feature declares a structural or behavioral characteristic of an instance of a Classifier or of the Classifier itself. Feature is an abstract metaclass. A structural feature refers to a static feature of a model element. In the metamodel, a StructuralFeature declares a structural aspect of a Classifier that is typed, such as an attribute. For example, it specifies the multiplicity and changeability of the StructuralFeature. StructuralFeature is an abstract metaclass. UmlAttribute A constraint is a semantic condition or restriction expressed in text. In the metamodel, a Constraint is a BooleanExpression on an associated ModelElement(s) which must be true for the model to be well formed. This restriction can be stated in natural language, or in different kinds of languages with well-defined semantics. Certain Constraints are predefined, others may be user defined. Note that a Constraint is an assertion, not an executable mechanism. The specification is written as an expression in a designated constraint language. The language can be specially designed for writing constraints (such as OCL), a programming language, mathematical notation, or natural language. If constraints are to be enforced by a model editor tool, then the tool must understand the syntax and semantics of the constraint language. Because the choice of language is arbitrary, constraints can be used as an extension mechanism. The constraint concept allows new semantics to be specified linguistically for a model element. In the metamodel a Constraint directly attached to a ModelElement describes semantic restrictions that this ModelElement must obey. UmlConstraint A dependency states that the implementation or functioning of one or more elements requires the presence of one or more other elements. In the metamodel, a Dependency is a directed relationship from a client (or clients) to a supplier (or suppliers) stating that the client is dependent on the supplier (i.e., the client element requires the presence and knowledge of the supplier element). A dependency specifies that the semantics of a set of model elements requires the presence of another set of model elements. This implies that if the source is somehow modified, the dependents probably must be modified. The reason for the dependency can be specified in several different ways (e.g., using natural language or an algorithm) but is often implicit. Whenever the supplier element of a dependency changes, the client element is potentially invalidated. After such invalidation, a check should be performed followed by possible changes to the derived client element. Such a check should be performed after which action can be taken to change the derived element to validate it again. In the metamodel a Multiplicity defines a non-empty set of non-negative integers. A set which only contains zero ({0}) is not considered a valid Multiplicity. Every Multiplicity has at least one corresponding String representation. In the metamodel a MultiplicityRange defines a range of integers. The upper bound of the range cannot be below the lower bound. The lower bound must be a nonnegative integer. The upper bound must be a nonnegative integer or the special value unlimited, which indicates there is no upper bound on the range. The stereotype concept provides a way of branding (classifying) model elements so that they behave as if they were instances of new virtual metamodel constructs. These model elements have the same structure (attributes, associations, operations) as similar non-stereotyped model elements of the same kind. The stereotype may specify additional constraints and required tagged values that apply to model elements. In addition, a stereotype may be used to indicate a difference in meaning or usage between two model elements with identical structure. In the metamodel the Stereotype metaclass is a subclass of ModelElement. Tagged Values and Constraints attached to a Stereotype apply to all ModelElements branded by that Stereotype. A stereotype keeps track of the base class to which it may be applied. The base class is a class in the metamodel (not a user-level modeling element) such as Class, Association, etc. If a model element is branded by an attached stereotype, then the CWM base class of the model element must be the base class specified by the stereotype or one of the subclasses of that base class. A tagged value allows information to be attached to any model element in the form of a "tagged value" pair (i.e., name = value). The interpretation of tagged value semantics is intentionally beyond the scope of CWM. It must be determined by user or tool conventions. It is expected that tools will define tags to supply information needed for their operations beyond the basic semantics of CWM. Such information could include code generation options, model management information, or user-specified semantics. Even though TaggedValues are a simple and straightforward extension technique, their use restricts semantic interchange of metadata to only those tools that share a common understanding of the specific tagged value names. umlValue The Any data type is used to indicate that an attribute or parameter may take values from any of the available data types. In CWM, the set of data types an Any attribute or parameter may assume includes the data types and enumerations described in this chapter plus any available instances of the Classifier class. There is no default value for data type Any. Boolean defines an enumeration that denotes a logical condition. The default for data type Boolean is false. The Float data type is used to indicate that an attribute or parameter may take on floating point numeric values. The number of significant digits and other representational details are implementation defined. The default for the Float data type is the value 0.0. Integer represents the predefined type of integers. An instance of Integer is an element in the (infinite) set of integers (..., -2, -1, 0, 1, 2, ...). The default for Integer is 0. Name defines a token which is used for naming ModelElements and similar usages. Each Name has a corresponding String representation. For purposes of exchange a name should be represented as a String. The default for the Name data type is an empty string. String defines a piece of text. Strings do not normally have a defined length; rather, they are considered to be arbitrarily long (practical limits on the length of Strings exist, but are implementation dependent). When String is used as the type of an Attribute, string length sometimes can be specified (see the Relational and Record packages for examples). The default for the String data type is an empty string. Time defines a statement which will define the time of occurrence of an event. The specific format of time expressions is not specified here and is subject to implementation considerations. There is no default for the Time data type. UnlimitedInteger defines a data type whose range is the nonnegative integers augmented by the special value "unlimited". It is used for the upper bound of multiplicities. The default for an UnlimitedInteger is the special value "unlimited". ck_ In the metamodel OrderingKind defines an enumeration that specifies how the elements of a set are arranged. Used in conjunction with elements that have a multiplicity in cases when the multiplicity value is greater than one. The ordering must be determined and maintained by operations that modify the set. The default value is ok_unordered. ok_ In the metamodel ScopeKind defines an enumeration that denotes whether a feature belongs to individual instances or an entire classifier. The default value is sk_instance. sk_ In the metamodel VisibilityKind defines an enumeration that denotes how the element to which it refers is seen outside the enclosing name space. The default value is vk_public. vk_ umlConstraint The StereotypeTaggedValues association links Stereotypes with the set of TaggedValues they require. TaggedValues cannot simultaneously participate in both the TaggedElement and StereotypeTaggedValues associations. The TaggedElement association links TaggedValues with the ModelElements that own them. TaggedValues cannot simultaneously participate in both the TaggedElement and StereotypeTaggedValues associations. The Behavioral metamodel depends on the following package: org.omg::CWM::ObjectModel::Core The Behavioral metamodel collects together classes and associations that describe the behavior of CWM types and provides a foundation for recording the invocations of defined behaviors. The elements of the Behavioral metamodel are shown in the following figure. OCL Representation of Behavioral Constraints Operations The operation hasSameSignature checks if the argument has the same signature as the instance itself. hasSameSignature ( b : BehavioralFeature ) : Boolean; hasSameSignature (b) = (self.name = b.name) and (self.parameter->size = b.parameter->size) and Sequence{ 1..(self.parameter->size) }->forAll( index : Integer | b.parameter->at(index).type = self.parameter->at(index).type and b.parameter->at(index).kind = self.parameter->at(index).kind ) The operation allOperations results in a Set containing all Operations of the Classifier itself and all its inherited Operations. allOperations : Set(Operation); allOperations = self.allFeatures->select(f | f.ockIsKindOf(Operations)) The operation allMethods results in a Set containing all Methods of the Classifier itself and all its inherited Methods. allOperations : Set(Method); allMethods = self.allFeatures->select(f | f.ockIsKindOf(Method)) Constraints [C-4-1] All Parameters should have a unique name. context BehavioralFeature inv: self.parameter->forAll(p1, p2 | p1.name = p2.name implies p1 = p2) [C-4-2] The type of the Parameters should be included in the Namespace of the Classifier. context BehavioralFeature inv: self.parameter->forAll( p | self.owner.namespace.allContents->includes (p.type) ) [C-4-3] The number of arguments must be the same as the number of parameters of the Operation. context CallAction inv: self.actualArgument->size = self.operation.parameter->size [C-4-4] An Interface can only contain Operations. context Interface inv: self.allFeatures->forAll( f | f.oclIsKindOf( Operation ) ) [C-4-5] An Interface cannot contain any ModelElements. context Interface inv: self.allContents->isEmpty [C-4-6] All Features defined in an Interface are public. context Interface inv: self.allFeatures->forAll( f | f.visibility = #public ) [C-4-7] If the realized Operation is a query, then so is the Method. context Method inv: self.specification->isQuery implies self.isQuery org.omg.cwm.objectmodel CWM BehavioralModule org.omg.java.cwm.objectmodel Argument is an expression describing how to determine an actual value passed in a CallAction. In the metamodel an Argument is a composite part of a CallAction and contains a meta-attribute, value, of type Expression. It states how the actual argument is determined when the owning CallAction is executed. umlValue A behavioral feature refers to a dynamic feature of a model element, such as an operation or method. In the metamodel, BehavioralFeature specifies a behavioral aspect of a Classifier. All different kinds of behavioral aspects of a Classifier, such as Operation and Method, are subclasses of BehavioralFeature. BehavioralFeature is an abstract metaclass. A call action is an action resulting in an invocation of an operation. The purpose of a CallAction is to identify the actual Arguments used in a specific invocation of an Operation. Interface is a named set of operations that specify the behavior of an element. In the metamodel, an Interface contains a set of Operations that together define a service offered by a Classifier realizing the Interface. A Classifier may offer several services, which means that it may realize several Interfaces, and several Classifiers may realize the same Interface. UmlInterface Operation is a service that can be requested from an object to effect behavior. An Operation has a signature, which describes the parameters that are possible (including possible return values). In the metamodel, an Operation is a BehavioralFeature that can be applied to instances of the Classifier that contains the Operation. Operation is the specification, while Method is the implementation. In the metamodel ParameterDirectionKind defines an enumeration that denotes if a Parameter is used for supplying an argument and/or for returning a value. The enumeration values are: The default value is pdk_in. pdk_ The Relationships metamodel depends on the following package: org.omg::CWM::ObjectModel::Core The Relationships metamodel collects together classes and associations that describe the relationships between object within a CWM information store. The Relationships metamodel describes to types of relationships: association and generalization. Association relationships record linkages between model elements. These linkages may represent simple linkages between model elements or aggregation ("is part of") relationships between model elements; aggregation relationships come in two forms -- shared and composite. Associations have two or more named ends that link them to instances of the classes connected by the association. Generalization relationships record arrangements of model elements into type hierarchies in a parent/child (or "is type of") fashion. Child types are said to "specialize", "subclass" or "subtype" their parental types, represent a subset of parental instances that fulfill the definition of the child type, and inherit the structural features (Attributes, AssociationEnd) and behavioral features (Operations, Methods) of their parents. Parental types are said to "generalize" their child types or to be "superclasses" or "supertypes" of their children. CWM generalization hierarchies support multiple inheritance; that is, child types may have more than one parental type and inherit the union of the features of all their parental types. Although called "hierarchies", multiple inheritance actually represents a directed acyclic graph of parental and child types. OCL Representation of Relationships Constraints Operations The operation allConnections results in the set of all AssociationEnds of the Association. allConnections : Set(AssociationEnd); allConnections = self.feature.oclIsKindOf(AssociationEnd) Constraints [C-5-1] An Association must have at least 2 AssociationEnds. context Association inv: self.allConnections->size > 1 [C-5-2] The AssociationEnds must have a unique name within the association. context Association inv: self.allConnections->forAll( r1, r2 | r1.name = r2.name implies r1 = r2) [C-5-3] At most one AssociationEnd may be an aggregation or composition. context Association inv: self.allConnections->select(aggregation <> #ak_none)->size <= 1 [C-5-4] If an Association has three or more AssociationEnds, then no AssociationEnd may be an aggregation or composition. context Association inv: self.allConnections->size >=3 implies self.allConnections->forall(aggregation = #ak_none) [C-5-5] The connected Classifiers of the AssociationEnds should be included in the Namespace of the Association, or be Classifiers with public visibility in other Namespaces to which the Association has access. context Association inv: self.allConnections->forAll(r | self.namespace.allContents->includes (r.type) ) or self.allConnections->forAll(r | self.namespace.allContents->excludes (r.type)) implies self.namespace.clientDependency->exists (d | d.supplier.oclAsType(Namespace).ownedElement->select (e | e.elementOwnership.visibility = #ak_public)->includes (r.type) or d.supplier.oclAsType(Classifier).allParents. oclAsType(Namespace).ownedElement->select (e | e.elementOwnership.visibility = #ak_public)->includes (r.type) or d.supplier.oclAsType(Package).allImportedElements->select (e | e.elementImport.visibility = #ak_public) ->includes (r.type) ) ) [C-5-6] An AssociationEnd must have an owning Association. context AssociationEnd inv: self.owner.oclIsKindOf(Association) [C-5-7] The Classifier of an AssociationEnd cannot be an Interface or a DataType if the association is navigable away from that end. context AssociationEnd inv: (self.type.oclIsKindOf (Interface) or self.type.oclIsKindOf (DataType)) implies self.owner->select (ae | ae <self)->forAll(ae | ae.isNavigable = #false) [C-5-8] An instance may not belong by composition to more than one composite Instance. context AssociationEnd inv: self.aggregation = #ak_composite implies self.multiplicity.max <= 1 [C-5-9] An AssociationEnd with composite or shared aggregation semantics must be owned by an Association. context AssociationEnd inv: self.aggregation = #ak_composite or self.aggregation = #ak_shared implies self.owner.oclIsKindOf(Association) org.omg.cwm.objectmodel CWM RelationshipsModule org.omg.java.cwm.objectmodel An association defines a semantic relationship between classifiers. Associations have two or more named ends. Associations with two or more ends are called "n-ary" whereas associations with exactly two ends are called "binary". Each end, depending upon its multiplicity, connects to zero or more instances of some classifier. In the metamodel, an Association is a declaration of a semantic relationship between Classifiers, such as Classes. Associations must have two, and may have more, association ends. Each end is connected to a Classifier; the same Classifier may be connected to more than one association end in the same association. (Refer to the ObjectModelÂ’s Instance package, below, for a description of how Associations are instantiated.) Because Associations are classifiers, they own and order their association ends (which are Attributes) via the ClassifierFeature association. In addition, because Associations are Classes, they can also own more traditional StructuralFeatures such as Attributes. Consequently, they may act in a manner similar to "association classes" described by some other object models. An association may represent an aggregation (i.e., a whole/part relationship). In this case, the association end attached to the whole element is designated, and the other association end represents the parts of the aggregation. Associations can be of three different kinds: (1) ordinary association, (2) composite aggregate, and (3) shareable aggregate. Since the aggregate construct can have several different meanings depending on the application area, CWM gives a more precise meaning to two of these constructs (i.e., association and composite aggregate) and leaves the shareable aggregate more loosely defined in between. Only binary Associations can have composite or sharable aggregation semantics. Composite aggregation is a strong form of aggregation which requires that a part instance be included in at most one composite at a time and that the composite object has sole responsibility for the disposition of its parts. This means that the composite object is responsible for the creation and destruction of the parts. In implementation terms, it is responsible for their memory allocation. If a composite object is destroyed, it must destroy all of its parts. It may remove a part and give it to another composite object, which then assumes responsibility for it. If the multiplicity from a part to composite is zero-to-one, the composite may remove the part and the part may assume responsibility for itself, otherwise it may not live apart from a composite. A consequence of these rules is that a composite aggregation implies propagation semantics (i.e., some of the dynamic semantics of the whole is propagated to its parts). For example, if the whole is copied or destroyed, then so are the parts as well (because a part may belong to at most one composite). A classifier on the composite end of an association may have parts that are classifiers and associations. At the instance level, an instance of a part element is considered "part of" the instance of a composite element. If an association is part of a composite and it connects two classes that are also part of the same composite, then an instance of the association will connect objects that are part of the same composite object of which the instance is part. A shareable aggregation denotes weak ownership (i.e., the part may be included in several aggregates) and its owner may also change over time. However, the semantics of a shareable aggregation does not imply deletion of the parts when an aggregate referencing it is deleted. Both kinds of aggregations define a transitive, antisymmetric relationship (i.e., the instances form a directed, non-cyclic graph). Composition instances form a strict tree (or rather a forest). An association end is an endpoint of an association, which connects the association to a classifier. Each association end is part of one association. The association ends of each association are ordered. In the metamodel, an AssociationEnd is part of an Association and specifies the connection of an Association to some other Classifier. Because AssociationEnds are a kind of StructuralFeature, they are owned and ordered by Association instances via the ClassifierFeature association. The StructuralFeatureType association is used to identify the Classifier to which the AssociationEnd is attached. Each AssociationEnd has a name and defines a set of properties of the connection. The multiplicity property of an association end specifies how many instances of the classifier at a given end (the one bearing the multiplicity value) may be associated with a single instance of the classifier at the other end. The association end also states whether or not the connection may be traversed towards the instance playing that role in the connection (the isNavigable attribute), that is, if the instance is directly reachable via the association. A generalization is a taxonomic relationship between a more general element and a more specific element. The more specific element is fully consistent with the more general element (it has all of its properties, members, and relationships) and may contain additional information. In the metamodel, a Generalization is a directed inheritance relationship, uniting a Classifier with a more general Classifier in a hierarchy. Generalization is a subtyping relationship; that is, an instance of the more general ("parent") Classifier may be substituted by an instance of the more specific ("child") Classifier. To understand inheritance fully, it is necessary to understand the concept of a full descriptor and a segment descriptor. A full descriptor is the full description needed to describe an instance of a metamodel object. It contains a description of all of the attributes, associations, and operations that the object contains. In a pre-object-oriented language, the full descriptor of a data structure was declared directly in its entirety. In an object-oriented language, the description of an object is built out of incremental segments that are combined using inheritance to produce a full descriptor for an object. The segments are the modeling elements that are actually declared in a model. Each classifier contains a list of features and other relationships that it adds to what it inherits from its ancestors. The mechanism of inheritance defines how full descriptors are produced from a set of segments connected by generalization.The full descriptors are implicit, but they define the structure of actual instances. Features of a classifier that have private visibility are not visible to descendants of the classifier. If a classifier has no parent, then its full descriptor is the same as its segment descriptor. If a classifier has one or more parents, then its full descriptor contains the union of the features from its own segment descriptor and the segment descriptors of all of its ancestors. No attribute, operation, or association end with the same signature may be declared in more than one of the segments (in other words, they may not be redefined). A method may be declared in more than one segment. A method declared in any segment supersedes and replaces a method with the same signature declared in any ancestor. If two or more methods nevertheless remain, then they conflict and the model is ill-formed. The constraints on the full descriptor are the union of the constraints on the segment itself and all of its ancestors. If any of them are inconsistent, then the model is ill-formed. In any full descriptor for a classifier, each method must have a corresponding operation. In a concrete classifier, each operation in its full descriptor must have a corresponding method in the full descriptor. An enumeration that denotes what kind of aggregation an Association defines. When placed on a target end, specifies the relationship of the target end to the source end. The default value is ak_none. ak_ The Instance metamodel depends on the following package: org.omg::CWM::ObjectModel::Core In addition to the metadata normally interchanged with CWM, it is sometimes useful to interchange specific data instances as well. The ObjectModelÂ’s Instance metamodel allows the inclusion of data instances with the metadata. OCL Representation of Instance Constraints Constraints [C-6-1] A DataValue originates from a Classifier that is a DataType. context DataValue inv: self.classifier.oclIsKindOf(DataType) [C-6-2] A DataValue has no Slots. context DataValue inv: self.valueSlot->isEmpty [C-6-3] An Object may only own Objects and DataValues. context Object inv: self.contents->forAll(c | c.oclIsKindOf(Object) or c.oclIsKindOf(DataValue)) [C-6-4] If an Object represents an association, at least two of its ends must be not be empty. context Object inv: self.classifier.oclIsKindOf(Association) implies self.slot.feature->iterate( ae ; cnt : Integer = 0 | if ae.oclIsKindOf(AssociationEnd) and ae.value.notEmpty then cnt + 1 else cnt end if ) > 1 [C-6-5] If the StructuralFeature describing a Slot is an AssociationEnd, the Classifier associated with the Object owning the Slot must be an Association. context Slot inv: self.feature.oclIsKindOf(AssociationEnd) implies self.value.classifier.oclIsKindOf(Association) org.omg.cwm.objectmodel CWM InstanceModule org.omg.java.cwm.objectmodel A data value is an instance with no identity. In the metamodel, DataValue is a child of Instance that cannot change its state, i.e. all operations that are applicable to it are pure functions or queries that do not cause any side effects. DataValues are typically used as attribute values. Since it is not possible to differentiate between two data values that appear to be the same, it becomes more of a philosophical issue whether there are several data values representing the same value or just one for each value. In addition, a data value cannot change its data type and it does not have contained instances. Each instance of Extent owns a collection of instances and is used to link such collections to their structural and behavioral definitions in CWM Resource packages. Because Extent is a subclass of package, it owns member instances via the ElementOwnership associaton. The instance construct defines an entity to which a set of operations can be applied and which has a state that stores the effects of the operations. In the metamodel Instance is connected to a Classifier that declares its structure and behavior. It has a set of attribute values matching the definition of its Classifier. The set of attribute values implements the current state of the Instance. Because Instance is an abstract class, all Instances are either Object or DataValue instances. The data content of an Instance comprises one value for each attribute in its full descriptor (and nothing more). The value must be consistent with the type of the attribute. An instance must obey any constraints on the full descriptor of the Classifier of which it is an instance (including both explicit constraints and built-in constraints such as multiplicity). An object is an instance that originates from a class. In the metamodel, Object is a subclass of Instance originating from a Class. The Class may be modified dynamically, which means that the set of features of the Object may change during its life-time. An object is an instance that originates from a class; it is structured and behaves according to its class. All objects originating from the same class are structured in the same way, although each of them has its own set of attribute slots. Each attribute slot references an instance, usually a data value or possibly, another object. The number of attribute slots with the same name fulfills the multiplicity of the corresponding attribute in the class. The set may be modified according to the specification in the corresponding attribute, e.g. each referenced instance must originate from (a specialization of) the type of the attribute, and attribute slots may be added or removed according to the changeable property of the attribute. UmlObject umlObject cwmlValue The Business Information package depends on the following package: org.omg::CWM::ObjectModel::Core The Business Information Metamodel provides general purpose services available to all CWM packages for defining business-oriented information about model elements. The business-oriented services described here are designed to support the needs of data warehousing and business intelligence systems; they are not intended as a complete representation of general purpose business intelligence metamodel. Business Information Metamodel services support the notions of responsible parties and information about how to contact them, identification of off-line documentation and support for general-purpose descriptive information. Three CWM classes "anchor" these services: ResponsibleParty, Document and Description, respectively. To aid in representing the diversity of organizational structures and documentation relationships that may be encountered in a business intelligence system, the metamodel provides robust relationships between the anchor classes and every model element in the CWM metamodel. The necessary robustness is achieved in several ways. First, every CWM model element may have zero or more instances of each anchor class associated with it. This means, for example, that a single Description instance can be used to describe many different model elements. Conversely, a single model element may be described by many different Description instances. Likewise, Document and ResponsibleParty instances can be associated in completely ad hoc ways with any model element. Extending this idea means, for example, that Description instances could be used to further describe ResponsibleParty and Document instance, if needed. Second, because they are Namespaces, the anchor classes can be organized into hierarchies using the ElementOwnership association. For instance, an organizational structure can be represented by a hierarchy of ResponsibleParty instances. Also, the internal structure of a document (i.e., its chapters, sections, subsections, etc.) might be represented by a hierarchy of Document instances. Finally, instances of the three anchor classes can be associated with any model element (via their individual associations to ModelElement) and referenced by multiple instances of any of the three anchor classes. Because of the strong containment of the ElementOwnership association in the ObjectModel, anchor class instances can only participate in one hierarchy, but there are no restrictions preventing anchor class instances embedded in a hierarchy from referencing, or being referenced by, other model elements (even other members of the same hierarchy). To illustrate some of the ways that the metamodel can be used, the following figure shows a simple document hierarchy with responsibility assignments and descriptive comments (boxes represent instances of metamodel classes and labelled lines represent metamodel associations connecting instances). In the example, the product plan document for the Widget product is composed of three subplans: a marketing plan, an engineering plan, and a resource plan. The relationships between the subplans documents is shown as a hierarchy with the product plan owning the three subordinate plans via the ElementOwnership association. Each part of the plan is assigned to a reponsible party using the ModelElementResponsibility association. Finally, Description instances are used to record roles for the responsible parties. OCL Representation of BusinessInformation Constraints [C-3-1] A Description may not describe itself. context Description inv: self.modelElement->forAll(p | p <> self) [C-3-2] A Document may not describe itself. context Document inv: self.modelElement->forAll(p | p <> self) [C-3-3] A ResponsibleParty may not describe itself. context ResponsibleParty inv: self.modelElement->forAll(p | p <> self) CWM org.omg.cwm.foundation BusinessInformationModule org.omg.java.cwm.foundation The ResponsibleParty class allows representation of entities within an information system that are in some way interested in receiving information about, or are otherwise responsible for, particular ModelElements. Each ResponsibleParty may own multiple sets of contact information, and a single ResponsibleParty may be associated with many ModelElements. ResponsibleParty instances may represent any entity appropriate to the system being modeled and need not be limited to people. For example, a ResponsibleParty instance might represent an individual such as "George Washington", a role (the "President"), or an organization ("Congress"), depending upon the needs of the system being modeled. Similarly, the precise semantics of the responsibility attribute are open to intrepretation and may be adapted on a system-by-system basis. Because ResponsibleParty instances are Namespaces, they can be organized into hierarchies of ResponsibleParty instances, capturing organizational structures or similar relationships. Instances of the Telephone class represent telephone contact information. Because telephones are first class objects within the CWM, they can be used for purposes beyond those associated with the CWM FoundationÂ’s Business Information concepts. A textual representation of the telephoneÂ’s type, such as "multi-line", or its usage, such as "home", "work", "fax", or "mobile". An Email instance identifies a single email address. Via a Contact instance, an email address can be associated with one or more ResponsibleParty instances. Email instances might, for example, be used by an automated tool to send an automatically generated email message to a ResponsibleParty instance responsible about some change of state for a particular ModelElement. Multiple Email instances may be associated with a single Contact instance and the ordering of the association between them may be used to represent the sequence in which the Email instances should be contacted. Because email addresses are first class objects within the CWM, they can be used for purposes beyond those associated with the CWMFoundationÂ’s Business Information concepts. Instances of the Location class represent physical locations. Note that the name of a Location is derived from its superclass, ModelElement. Because Locations are first class objects within the CWM, they can be used for purposes beyond those associated with the CWM FoundationÂ’s Business Information concepts. If additional attributes about Location instances are required, they should be added by creating subtypes of the Location class and placing the additional attributes therein. Each Contact instance collects together the various types of related contact information. Each Contact instance can be associated with multiple Email, Location and Telephone instances. Conversely, each Email, Location, ResourceLocator and Telephone instance can be associated with many Contact instances. The ordering constraints on the associations between these classes and the Contact class can be used to represent a prioritized sequence in which the various types of contact information should be used. A particular ResponsibleParty instance may have multiple instances of Contact associated with it via the ResponsiblePartyContact association. This association is ordered to support representation of the sequence in which Contact instances should be used. For example, a ResponsibleParty instance representing an employee might be associated with Contact instances representing their office, home, and mobile contact information with an indication that the employee should be contacted first at the office, then at home, and finally via their mobile phone. To maximize flexibility of the metamodel, Contact instances may provide contact information for multiple ResponsibleParty instances. Instances of the Description class contain arbitrary textual information relevant to a particular ModelElement. While Description instances may contain any desired textual information, they will typically contain documentation or references to external reference information about the owning ModelElement. Any ModelElement may have multiple Description instances associated with it. Indeed, a ModelElement instance that is a Description instance may itself have multiple Description instances linked to it. Also, a hierarchies of Description instances can be constructed. Description instances are meant to hold descriptive textual information that will be stored in the metamodel itself. In contrast, Document instances are meant to describe the location documentary information stored outside the metamodel. The Document class represents externally stored descriptive information about some aspect of the modeled system. An instance of Document might be associated with one or more ModelElements. The name of a Document instance is derived from its superclasses. Although the purposes of the Description and Document types may overlap somewhat, their chief distinction is that Description instances are stored with the CWM metadata whereas Documentation instances are stored externally to the CWM metadata. Although there is an implication here that Documentation instances might represent more voluminous information than Description instances, there is no particular requirement that this be so. Because Documentation instances are themselves Namespace instances, hierarchical relationships between various externally stored documents can be represented. Instances of the ResourceLocator class provide a general means for describing the resources whose location is not defined by a traditional mailing address. For example, a ResourceLocator instance could refer to anything from a location within a building ("Room 317, third file cabinet, 2nd drawer") to a web location ("www.omg.org"). Because they are first class objects in the CWM, ResourceLocator instances may also be used for purposes beyond those associated with the CWM Foundation's Business Information concepts. The ContactEmail association indicates the Email instances relevant used by Contact instances. The DocumentDescribes association connects a Document instance with the ModelElement instances to which it pertains. The DataTypes package depends on the following packages: org.omg::CWM::ObjectModel::Core The CWM DataTypes metamodel supports definition of metamodel constructs that modelers can use to create the specific data types they need. Although the CWM Foundation itself does not contain specific data type definitions, a number of data type definitions for widely used environments are provided (in the CWM Data Types chapter) as examples of the appropriate usage of CWM Foundation classes for creating data type definitions. OCL Representation of DataTypes Constraints [C-4-1] A TypeAlias instance cannot alias itself. context TypeAlias inv: self.type <> self [C-4-2] A Union can have at most one default UnionMember instance. context Union inv: self.allFeatures->select(isDefault)->size <= 1 CWM org.omg.cwm.foundation DataTypesModule org.omg.java.cwm.foundation The Enumeration class is intended as a starting point from which enumerated data types can be created. An enumerated data type is a collection of identifiers often used as the permitted states that some other attribute or property of the enumerated type may take. The isOrdered attribute of an Enumeration instance is used to determine if the ordered constraint on the EnumerationLiterals association is relevant for the enumeration. The particular ordering of EnumerationLiteral instances is obtained from the ordered constraint on the association even if the value attributes of the EnumerationLiteral instances contain non-null values that might be used to determine ordering. This is done to provide more flexible ordering semantics. An instance of Enumeration is also required to create a range data type. Refer to the EnumerationLiteral class for details. If True, the ordered constraint on the EnumerationLiterals association is relevant. Otherwise, the ordering of EnumerationLiteral instances is considered unspecified. EnumerationLiteral instances describe the enumeration identifiers, and possibly the values, associated with an enumerated data type. Enumeration identifiers are contained in the name attribute derived from the EnumerationLiteral instanceÂ’s ModelElement superclass. EnumerationLiteral instances may also be used to define expression-based values such as ranges. To do so, simply state the membership expression in the instanceÂ’s value. For example, a range literal can be created by setting the value attribute to "m..n", where m represents the lower bound of the range, and n, the upper bound. In this way, ranges and other more complicated expressions can be intermixed with simple enumeration literals. For example, an enumeration might contain the literals "1", "2", "4..7", and "> 10". Consequently, a simple range data type can be created with an Enumeration instance that owns a single EnumerationLiteral instance. For example, a data type for positive integers could be created as shown in the following instance diagram. A model attribute of this data type might then be declared as "posInt : PositiveInteger". umlValue typedef Foundation.DataTypes.ProcedureExpression QueryExpression; The Union class represents programming language unions and similarly structured data types. Because of the diversity of union semantics found across software systems, the Union and UnionMember classes are likely candidates for specialization to better capture union semantics in specific language extension packages. A discriminated Union has a collection of UnionMembers that determine the sets of contents that the Union may contain. Such Unions have an attribute called the discriminator that identifies the memberCase value of the UnionMember that the Union currently contains. The discriminator is found via the UnionDiscriminator association to StructuralFeature. The discriminator may be embedded within UnionMembers or may be located outside the discriminator. If it is located within UnionMembers, the discriminator should occur in every UnionMember at the same location (often, the first). Undiscriminated unions (for example, a C language union) are also supported, but have an empty discriminator reference, and the memberCase attribute of the UnionMembers it contains is ignored. Undiscriminated Unions are often used to represent alternate views of a single physical storage area. A fine degree of control over this aspect of Unions may be obtained by creating a class that derives from both UnionMember and FixedOffsetField (in the CWM Record package) and setting the offset attribute instances of that class accordingly. CwmUnion UnionMembers are described as features of a Union and each represents one of the members of a Union. Note, however, that multiple case values can map to a single UnionMember. If isDefault is true, the union member is the default member. UnionMember instances are allowed to have a memberCase and be the default case. UnionMember instances often represent structured storage areas. A particular UnionMember may be associated with a Classifier that describes its internal structure via the StructuralFeatureType association (defined in the ObjectModel::Core package). For example, the Record::Group class, itself a Classifier, can be used as the type of a UnionMember in a manner completely analogous to how it is used to describe the type of a structured field (see the instance diagrams in the Record metamodel chapter for details). The EnumerationLiterals association links enumeration literals to the Enumeration instances that contain them. If the EnumerationÂ’s isOrdered attribute is True, the ordering constraint on the association is relevant. Otherwise, it is ignored. The UnionDiscriminator association connects a Union instance with the StructuralFeature instance that can be used to determine which UnionMember instance is currently present in the Union instance. This "discriminating" attribute may be a feature of the UnionMembers themselves or may be a feature of some Classifier that contains the Union instance as one of its Features. In the former case, the discriminating feature will usually be present at the same offset in each UnionMember instance. If the discriminator reference is empty for a particular Union instance, it is considered to be an "undiscriminated" Union and determination of the current UnionMember residing in the Union is usage-defined. The Expressions package depends on the following packages: org.omg::CWM::ObjectModel::Core The CWM Expressions metamodel provides basic support for the definition of expression trees within the CWM. The intent of the Expressions metamodel is to provide a place for other CWM packages (such as Transformation) and CWM compliant tools to record shared expressions in a common form that can be used for interchange and lineage tracking. The expression concept in the CWM Foundation takes a functional view of expression trees, resulting in the ability of relatively few expression types to represent a broad range of expressions. Every function or traditional mathematical operator that appears in an expression hierarchy is represented as a FeatureNode. For example, the arithmetic plus operation “a + b” can be thought of as the function “sum(a, b).” The semantics of a particular function or operation are left to specific tool implementations and are not captured by the CWM. The hierarchical nature of the CWMÂ’s representation of expressions is achieved by the recursive nature of the OperationArgument association. This association allows the sub-hierarchies within an expression to be treated as actual parameters of their parent nodes. OCL Representation of Expressions Constraints [C-5-1] A FeatureNode that has parameters other than the"this" parameter represents a Feature that is also an Operation. context FeatureNode inv: if self.feature.ownerScope = #instance then self.argument->size > 1 implies self.feature.oclIsKindOf(Operation) else self.argument->size > 0 implies self.feature.oclIsKindOf(Operation) endif [C-5-2] If the FeatureNode represents an instance-scope feature, the first argument is a "this" or "self" argument; that is, the object invoking the feature. The convention is enforced by checking that the type of the first argument is the same as the type of the feature. context FeatureNode inv: self.feature.ownerScope = #instance implies self.argument->first.type.allFeatures->includes(self.feature) [C-5-3] If the FeatureNode represents a BehavioralFeature, the number of arguments must be equal to the number of the BehavioralFeatureÂ’s parameters, plus one for the “this” parameter if the BehavioralFeature is of instance scope. context FeatureNode inv: self.feature.oclIsKindOf(BehavioralFeature) implies (if self.feature.ownerScope = #instance then self.argument->size = self.feature.oclAsType(BehavioralFeature).parameters->size + 1 else self.argument->size = self.feature.oclAsType(BehavioralFeature).parameters->size endif) CWM org.omg.cwm.foundation ExpressionsModule org.omg.java.cwm.foundation All node types within an expression are derived from the ExpressionNode type. An expression is stored as a collection of instances of the subtypes of ExpressionNode arranged in a hierarchical fashion. The ExpressionNode instance at the top (or “root”) of the hierarchy represents the value of the expression and serves as a starting point for expression evaluation. Refer to the descriptions of the subtypes of ExpressionNode (ElementNode, ConstantNode, and FeatureNode) for additional information about the representation of expressions. One important purpose for providing storage of expressions as a general feature of the CWM is to promote sharing them between tools and to provide a means for recording lineage relationships between components within expressions. Specific details of the implementation of expression operators are left to the implementing tools. When ExpressionNode is used as the type of an Attribute, an instance of the Attribute can contain either an expression tree as described here or a textual representation of the expression in body and language values of in an attribute of type Expression (defined ObjectModel). The expression attribute is provided for the latter usage. To obtain CWMÂ’s sharing and lineage tracking features for elements within an expression, the expression must be represented as an expression hierarcy. umlValue An ElementNode is a node in an expression that references some ModelElement instance. This subclass of ExpressionNode allows an expression to reference any CWM model element that is not a Feature and cannot, therefore, be represented as a FeatureNode. Typically, use of this subclass of ExpressionNode implies that a tool attempting to evaluate the expression will be able to determine if the referenced ModelElement instance is also an instance of some interesting subclass of ModelElement that contains a value of interest in the expression. The FeatureNode class represents ExpressionNode instances that are features (i.e., attributes or operations) of some Classifier instance within the CWM. A FeatureNode with a null OperationArgument association represents either a parameter-less operation or an attribute value obtained from some StructuralFeature instance. The OperationArgument association identifies and orders the actual arguments of an Operation indicated by the FeatureNode end of the association. This association is meaningful only if the FeatureNode references, via the NodeFeature association, a Feature that is also an Operation. The association is not meaningful under other circumstances. The KeysIndexes package depends on the following package: org.omg::CWM::ObjectModel::Core Keys and indexes as means for specifying instances and for identifying alternate sortings of instances are epresented in the CWMFoundation so that they can be shared among the various data models that employ hem. The CWM Foundation defines the base concepts (uniqueness and relationships implemented as keys) pon which more specific key structures can be built by other CWM and tool-specific packages. The concepts of key and index have been placed in the CWM Foundation because they are available in many types of data resources. In the CWM Foundation class and association descriptions that follow, relational model examples are frequently used when discussing the definition and usage of key and index types. This is done because of the wide-spread availability of relational systems and is thought to promote an understanding of the underlying concepts. These concepts, however, are no less applicable to other data models as well. The two central classes for representing the concept of keys are UniqueKey and KeyRelationship. UniqueKey instances correspond to the notion that keys represent the identity of instances -- similar to the relational modelÂ’s concept of a primary key or an object modelÂ’s concept of an object identity. In contrast, KeyRelationship instancescorrespond to the notion that keys embedded in an instance can be used to determine the identity of other related instances -- similar to the relational model concept of foreign key and the object model concept of a reference. Consequently, UniqueKey and KeyRelationship are best thought of as representing roles that collections of Features of Classifiers play rather than Classifiers describing the internal structure of keys. Representing keys as roles rather than structural entities provides greater flexibility and allows the reuse of Features in multiple keys and in differing relationships to each other. Associations within the KeysIndexes package describe how UniqueKey and KeyRelationship instances describe the roles they play for various Class instances and the StructuralFeature instances they contain. OCL Representation of KeysIndexes Constraints [C-6-1]The isAscending attribute is valid only if the isSorted attribute is True. context IndexedFeature inv: self.isAscending->notEmpty implies self.index.isSorted [C-6-2] A KeyRelationship instance must be owned by one and only one Class instance. context KeyRelationship inv: (self.namespace->size = 1) and self.namespace.oclIsKindOf(Class) [C-6-3] An UniqueKey instance must be owned by one and only one Class instance. context UniqueKey inv: (self.namespace->size = 1) and self.namespace.oclIsKindOf(Class) CWM org.omg.cwm.foundation KeysIndexesModule org.omg.java.cwm.foundation Instances of the Index class represent the ordering of the instances of some other Class, and the Index is said to "span" the Class. Indexes normally have an ordered set of attributes of the Class instance they span that make up the "key" of the index; this set of relationships is represented by the IndexedFeature class that indicates how the attributes are used by the Index instance. The Index class is intended primarily as a starting point for tools that require the notion of an index. The KeyRelationshipFeatures association links KeyRelationship instances with the StructuralFeature instances that comprise their key. The Software Deployment package depends on the following packages: org.omg::CWM::ObjectModel::Core org.omg::CWM::Foundation::BusinessInformation org.omg::CWM::Foundation::TypeMapping The Software Deployment package contains classes to record how the software in a data warehouse is used. A software package is represented as a SoftwareSystem object, which is a subtype of Subsystem. A SoftwareSystem may reference one or more TypeSystems that define the datatypes supported by the SoftwareSystem. The mappings between datatypes in different TypeSystems may be recorded as TypeMappings, as described in the TypeMapping metamodel. The separate components of a software package are each represented as Components that are either owned or imported by the SoftwareSystem. When a SoftwareSystem is installed, the deployment is recorded as a DeployedSoftwareSystem and a set of DeployedComponents. A DeployedComponent represents the deployment of a specific Component on a specific computer. Dependencies between DeployedComponents on the same computer may be documented as Usage dependencies between them. Individual computers are represented as Machine objects, located at a Site. A Site represents a geographical location, which may be recorded at any relevant level of granularity, e.g. a country, a building, or a room in a building. Hierarchical links between Sites at different levels of granularity may be documented. A DataManager is a DeployedComponent such as a DBMS or file management system that provides access to data. It may be associated with one or more data Packages identifying the Schema, Relational Catalog, Files or other data containers that it provides access to. A DataProvider is a DeployedComponent that acts as a client to provide access to data held by a DataManager. For example, an ODBC or JDBC client on a specific Machine would be represented as a DataProvider. A DataProvider may have several ProviderConnections, each identifying a DataManager that may be accessed using the DataProvider. If a DataProvider uses a name for a data Package that is different from the actual name used by the DataManager, a PackageUsage object can be added to record this. As a DataProvider is a subtype of DataManager, it is possible for a DataProvider to access data from a DataManager which is actually a DataProvider acting as a client to yet another DataManager. The model for the Software Deployment package is shown in three diagrams. The first diagram shows the objects related to software deployment, while the second diagram displays the DataManager and DataProvider area of the model. The third diagram shows the inheritance structure for all the classes in the Software Deployment package. OCL Representation of SoftwareDeployment Constraints [C-8-1] A PackageUsage must have a single Package (or subtype of Package) as its supplier context PackageUsage inv: self.supplier->size=1 and self.supplier->at(1).oclIsKindOf(Package) [C-8-2] A ProviderConnection must not associate a DataProvider with itself context ProviderConnection inv: self.dataManager <> self.dataProvider [C-8-3] A Site must not have a containingSite reference that refers to itself. context Site inv: self.containingSite -> forAll (c | c <> self) org.omg.cwm.foundation CWM SoftwareDeploymentModule org.omg.java.cwm.foundation A Site represents a geographical location. It provides a grouping mechanism for a group of machines at the same location. Sites may be documented at different levels of granularity; containment links may be used to record hierarchical relationships between Sites. Identifies the type of the software product. One of the following predefined values should be used if appropriate: OS, DBMS, MDDB, FileSystem, ODBC, JDBC or Application. This is used in conjunction with the type attribute to provide additional information about the type of the software product. For some of the predefined types, suggested subtype values are listed below: For an Operating System product (type OS): AIX, Linux, MVS, NT, Solaris, SunOS, VMS or Windows. For a Database Management System product (type DBMS): DB2, DMS II, IMS, Informix, Oracle, SQLServer or Sybase. For a Multidimensional Database product (type MDDB): Essbase or Express. A DeployedComponent represents the deployment of a Component on a specific Machine. It may represent the deployment of any type of Component. However, if the Component is part of a SoftwareSystem, the DeployedComponent should be part of a DeployedSoftwareSystem. Usage dependencies may be used to document that one DeployedComponent uses another DeployedComponent. A DeployedSoftwareSystem represents a deployment of a SoftwareSystem. Its associated DeployedComponents identify the individual Component deployments that constitute the DeployedSoftwareSystem. These DeployedComponents are not necessarily all deployed on the same Machine. A DataManager represents a DeployedComponent that manages access to data. For example, a deployed DBMS or File Management System would be represented as a DataManager. The DataManager may be associated with one or more data Packages identifying the Schema, Relational Catalog, Files, or other data container that it provides access to. A DataProvider is a deployed software Component that acts as a client to provide access to data that is managed by another product. For instance, a DataProvider might represent a deployed ODBC or JDBC product. The DataProvider may have resourceConnection references to ProviderConnections identifying the DataManagers to which it provides access. A Component represents a physical piece of implementation of a system, including software code (source, binary or executable) or equivalents such as scripts or command files. A Component is a subtype of Classifier, and so may have its own Features, such as Attributes and Operations. Deployment of a Component on a specific Machine is represented as a DeployedComponent. A PackageUsage represents a usage of a Package. It is particularly relevant in situations where a specific usage uses an alternative name for the Package, as this alternative name can be recorded using the packageAlias attribute. For example, if a DataProvider representing an ODBC or JDBC client uses a name for a relational database that is different from the dataPackage name used by the RDBMS server, a PackageUsage that has the relevant ProviderConnection as client and the serverÂ’s data Package as supplier can be added. Its packageAlias attribute can be used to record the name by which the data Package is known to the DataProvider. This associates the Package(s) containing the definition of the data with the DataManager that is used to access it. For example, it may be used to associate a Schema, Relational Catalog or File with the DataManager that manages access to it. The TypeMapping package depends on the following packages: org.omg::CWM::ObjectModel::Core The TypeMapping package supports the mapping of data types between different systems. The purpose of these mappings is to indicate data types in different systems that are sufficiently compatible that data values can be interchanged between them. Multiple mappings are allowed between any pair of types and a means of identifying the preferred mapping is provided. OCL Representation of TypeMapping Constraints [C-8-1] The sourceType and targetType references may not refer to the same Classifier instance. context TypeMapping inv: self.sourceType <> self.targetType [C-8-2] A TypeSystem may own only Classifiers and TypeMappings. context TypeSystem inv: self.ownedElement->forAll( e | e.oclIsKindOf(Classifier) or e.oclIsKindOf(TypeMapping)) CWM org.omg.cwm.foundation TypeMappingModule org.omg.java.cwm.foundation TypeMapping instances permit the creation of mappings between data types defined within different environments and are used to indicate data type compatibilities that permit direct assignment of values from one environment (the "source" type) into equivalent values in another environment (the "target" type). For example, an integer field data type in a record-oriented DBMS (the source type) might be mapped to a compatible integer data type in a relational DBMS (the target type). Whereas the actual transfer of data values between environments is accomplished using the CWMÂ’s Transformation package, TypeMapping instances can be used the identify both the permissible and preferred mappings between data types. Value interchange between a pair of data types is considered permissible if a TypeMapping instance is defined for the pair. A TypeMapping instance is considered the preferred mapping if the instanceÂ’s isBestMatch attribute has the value true. Typically, there will be one TypeMapping Instance between a pair of data types that is considered the preferred mapping. To promote flexible use of this feature, there is no requirement that a preferred TypeMapping instance must be identified between a pair of data types nor are multiple preferred instances prohibited. In these latter cases, however, the precise semantics are usage-defined. Interchange between data types defined by non-preferred mappings may often function as intended. However, the isLossy boolean may be set to indicate that such interchanges may be subject to validity restrictions in certain circumstances. For example, it may be valid to move data values from a 32-bit integer data type to a 16-bit integer data type as long as the actual values in the 32-bit underlying data type do not exceed the range permitted for 16-bit integers. The CWM Foundation leaves the understanding and handling of such differences to individual tools. If such differences must be modeled, consider using the CWM Transformation package to filter data values during interchange. TypeMapping instances are unidirectional, so two instances are required to show that a data type pair can be mutually interchanged between environments. Instances of the TypeSystem class collect together the data types (subclasses of Classifier) defined by a software system and the TypeMapping instances defining how they are mapped to data types in other TypeSystems. TypeMapping instances collected by a TypeSystem instance include both those in which the software systemÂ’s data types act as sources and as targets of mappings. Classifiers and TapeMappings are maintained in a single collection via the ElementOwnership association but can be distinguished by their respective types. Because it is a Package, a TypeSystem can also serve to collect together the Classifier instances for a particular software system. The MappingTarget association indicates the exposed data type for a particular TypeMapping instance. The Relational package describes data accessible through a relational interface such as a native RDBMS, ODBC, or JDBC. The Relational package is based on the [SQL] standard section concerning RDBMS catalogs. The scope of the top level container, Catalog, is intended to cover all the tables a user can use in a single statement. A catalog is also the unit which is managed by a data resource. A catalog contains schemas which themselves contain tables. Tables are made of columns which have an associated data type. The Relational package uses constructs in the ObjectModel package to describe the object extensions added to SQL by the [SQL] standards. The Relational package also addresses the issues of indexing, primary keys and foreign keys by extending the corresponding concepts from the Foundation packages. The Relational package depends on the following packages: org.omg::CWM::ObjectModel::Behavioral org.omg::CWM::ObjectModel::Core org.omg::CWM::ObjectModel::Instance org.omg::CWM::Foundation::DataTypes org.omg::CWM::Foundation::KeysIndexes The Relational package references the ObjectModel and Foundation packages. OCL Representation of Relational Constraints [C-1] temporaryScope is valid only if the isTemporary is True. context Tabl e inv: self.temporaryScope.notEmpty implies self.isTemporary=True [C-2] checkOption is valid only if isReadOnly is False. context View inv: self.checkOption implies self.isReadOnly=False [C-3] scale is valid only if precision is specified. context Column inv: self.scale.nonEmpty implies self.precision.notEmpty CWMRDB org.omg.cwm.resource RelationalModule org.omg.java.cwm.resource Used in Trigger. It indicates if the trigger is called once per statement execution or before/after each row of the table is modified. Used in Triggers. It indicates if the trigger activity is run before or after the statement or row is modified. Used in Foreign Keys Indicates if the Foreign Key validation should be deferred to the end of the transaction or executed immadiately at the end of the statement. This is the value used at the beginning of a transaction. It can be changed within a transaction. Used in Trigger. Indicates what types of events are using the current Trigger. Used in Column. Indicates if a Column may contain null values. Used in Procedure. Indicates if the Procedure is a Function or a Procedure Used in Foreign Key. It indicates the action taken on the row containing a foreign key value, when the primary key value referenced is deleted or updated. The name of the default character set used for the values in the column. This field applies only to columns whose datatype is a character string. RelationalColumnSet CwmColumnSet A catalogued set of columns, which may be Table or View. Note for typed tables: It is assumed that the typed table will own a set of columns conforming to the type they are OF. This set of columns allows the manipulation of the table by products which ignore this [SQL] extension. It also allows the columns of type REF, to be copied to a column with a SCOPE reference. A view is a non-materialized set of rows, defined by the associated query. The query associated with the View. The query result must match the set of Columns associated with the View (in parent class ColumnSet) The length of fixed length character or byte strings. Maximum length if length is variable. Indicates if null values are valid in this column. Note: Default values for Column data are provided in initialValue in the UML Attribute class (the class from which the Column class inherits). The name of the collation sequence used to sort the data values in the column. This applies only to columns whose datatype is a form of character string. The name of the character set used for the values in the column. This field applies only to columns whose datatype is a character string. A Foreign Key associates columns from one table with columns of another table. Associates an index with its columns. This is really an association (link) class. It is associated with one index and one column. CwmRowSet The Record package covers the basic concept of a record and its structure. The package takes a broad view of the notion of record, including both traditional data records such as those stored in files and databases, as well as programming language structured data types. In fact, the concepts described here can be used as a foundation for extension packages describing any information structure that is fundamentally hierarchical, or "nested," in nature such as documents, questionnaires, and organizational structures. The Record package depends on the following packages: org.omg::CWM::ObjectModel::Core org.omg::CWM::ObjectModel::Instance Because of the antiquity of many record-based models, individual system implementations employing record models may have unusual features (such as occurs-depending arrays, various COBOL rename/remapping semantics, etc.) that are not shared with other implementations. When such features are limited to single implementations or languages, they have been purposefully left out of the Record metamodel. Rather, unusual features of this sort should be placed into extension packages designed to meet the needs of those implementations or languages. For example, record structuring features endemic to the COBOL language have been placed in the COBOLData metamodel in the CWMX package described in Volume 2 and do not appear here. In this way, COBOL-only features do not burden other record oriented implementations unnecessarily. OCL Representation of Record Constraints [C-1] The owner of a Field and the type of a Field may not refer to the same Classifier instance. context Field inv: self.owner <> self.type [C-2] The scale attribute is valid only if the precision attribute is specified. context Field inv: self.scale->notEmpty implies self.precision->notEmpty [C-3] The precision attribute is valid only if the length attribute is not specified. context Field inv: self.precision->notEmpty implies self.length->isEmpty::filely one CWMREC org.omg.cwm.resource RecordModule org.omg.java.cwm.resource A RecordDef is an ordered collection of Fields representing the structure of a Record. Examples of RecordDefs include definitions of language-specific data structures database records IMS segments The internal structure of a RecordDef instance is constructed by adding Field instances as features (using the ElementOwnership association) and pointing each Field instanceÂ’s inherited type reference to the Classifier instance representing the FieldÂ’s data type. The referenced instance can be either a primitive data type (an instance of DataType, such as "integer") or a structured data type (such as a Group instance). Refer to the example for more details of the relationships between RecordDefs, Fields, Records, and their values. Instances of FixeOffsetField represent fields that have a fixed location in a record. FixedOffsetFields can be used as a foundation for recording details of physical record layouts and as a means of representing the internal structure of undiscriminated (ie, C-type) unions. A RecordFile is the definition of a file. It may have one or more RecordDefs, defining the structure of the records in the file. Each of these RecordDefs defines a valid structure for records in the file. Subclasses of RecordFile in extensions to support specific languages and systems may be used to represent specific types of files such as COBOL CopyLib files and C-language header files. Physical deployments of a RecordFile can be found via the DataManagerDataPackage association in the SoftwareDeployment package . CwmRecordSet The CWM Multidimensional metamodel is a generic representation of a multidimensional database. Multidimensional databases are OLAP databases that are directly implemented by multidimensional database systems. In a multidimensional database, key OLAP constructs (dimensions, hierarchies, etc.) are represented by the internal data structures of a ultidimensional database server, and common OLAP operations (consolidation, drill-down, etc.) are performed by the server acting on those data structures. Multidimensional databases are often classified as "physical OLAP" or "MOLAP" (memory-based OLAP) databases. Multidimensional databases offer enhanced performance and flexibility over OLAP systems that simulate multidimensional functionality using other technologies (e.g., relational database or spreadsheet): Performance: Multidimensional databases provide rapid consolidation times and formula calculations, and consistent query response times regardless of query complexity. This is accomplished, in part, through the use of efficient cell storage techniques and highly-optimized index paths. Flexibility: The specification and use of multidimensional schemas and queries (including the design of cubes, dimensions, hierarchies, member formulas, the manipulation of query result sets, etc.) can be accomplished in a relatively straight-forward manner, since the server directly supports (and exposes) the multidimensional paradigm. The CWM Multidimensional metamodel does not attempt to provide a complete representation of all aspects of commercially available, multidimensional databases. Unlike relational database management systems, multidimensional databases tend to be proprietary in structure, and there are no published, widely agreed upon, standard representations of the logical schema of a multidimensional database. Therefore, the CWM Multidimensional Database metamodel is oriented toward complete generality of specification. Tool-specific extensions to the metamodel are relatively easy to formulate, and several examples are provided in Volume 2, Extensions, of the CWM Specification. The Multidimensional package depends on the following packages: org.omg::CWM::ObjectModel::Core org.omg::CWM::ObjectModel::Instance The major classes and associations of the Multidimensional metamodel are shown in Figure 11-1. Schema is the container of all elements comprising a Multidimensional model. It also represents the logical unit of deployment of a Multidimensional database instance. Dimension represents a physical dimension in a Multidimensional database. Whereas the OLAP metamodel defines “dimension” as a purely conceptual entity, this Dimension represents the dimension object exposed by the programming model of a Multidimensional database. A Dimension may reference other instances of Dimension to form arbitrarily complex dimensional structures (e.g., hierarchies with varying levels of detail). DimensionedObject represents an attribute of Dimension. Examples of DimensionedObjects include measures (variables), formulas, consolidation functions, member alias names, etc. DimensionedObjects are contained by the Schema and referenced by the Dimensions that use them. MemberSet represents the collection of Members associated with an instance of Dimension, and MemberValue represents an instance value of a Member. MemberSet, Member and MemberValue enable the specification and interchange of both M1-level Multidimensional models and associated M0-level data values. Figure 11-2 illustrates the inheritance of the Multidimensional classes from metaclasses of the Object Model. OCL Representation of Multidimensional Constraints [C-1] A Dimension may not reference itself as a component, nor as a composite. context Dimension inv: self.component->excludes( self ) inv: self.composite->excludes( self ) The transitive closure of components of an instance of Dimension must not include the Dimension instance. The transitive closure of composites of an instance of Dimension must not include the Dimension instance. CWMMDB org.omg.cwm.resource MultidimensionalModule org.omg.java.cwm.resource CwmDimension CwmDimension CwmMemberSet XML is rapidly becoming a very important type of data resource, especially in the Internet environment. On the one hand, HTML is evolving to be XML-compliant; in the near future, all HTML documents can be expected to become valid XML documents. On the other hand, XML is quickly becoming the standard format for interchange of data and/or metadata (e.g., XMI). Therefore, XML documents (or streams) representing data and/or metadata can be expected to appear everywhere. The XML package contains classes and associations that represent common metadata describing XML data resources. It is based on XML 1.0 [XML]. XML Schema is an ongoing activity in the W3C. As future standards are adopted by the W3C on XML Schema, this package will be revised and extended accordingly. This section provides a description of the main features of the XML package. An XML schema contains a set of definitions and declarations, in the form of XML element type definitions. An XML element type may contain a set of XML attributes and/or a content model. An attribute can have one of the following defaults: required, implied, default, or fixed. The content model can be one of the following types: empty, any, mixed, or element. Except for the empty content model, a content model consists of constituent parts, particularly element type references. The allowed occurrence of the constituents can be one of the following types: one, zero or one, zero or more, or one or more. An any content model consists of any element types. A mixed content model consists of character data and specified element type references. An element content model consists of specified element type references and/or element content models. An element content model can be one of the following types: choice or sequence. The XML package depends on the following packages: omg.org::CWM::ObjectModel::Core omg.org::CWM::ObjectModel::Instance omg.org::CWM::Foundation::DataTypes The metamodel diagram for the XML package is split into two parts. The first diagram shows the XML classes and associations, while the second shows the inheritance hierarchy. OCL Representation of XML Constraints None CWMXML org.omg.cwm.resource XMLModule org.omg.java.cwm.resource xmlAttribute XmlAttribute XmlAttribute xml_ XmlElement XmlElement A key aspect of data warehousing is to extract, transform, and load data from operational resources to a data warehouse or data mart for analysis. Extraction, transformation, and loading can all be characterized as transformations. In fact, whenever data needs to be converted from one form to another in data warehousing, whether for storage, retrieval, or presentation purposes, transformations are involved. Transformation, therefore, is central to data warehousing. The Transformation package contains classes and associations that represent common transformation metadata used in data warehousing. It covers basic transformations among all types of data sources and targets: object-oriented, relational, record, multidimensional, XML, OLAP, and data mining. The Transformation package is designed to enable interchange of common metadata about transformation tools and activities. Specifically it is designed to: 1. Relate a transformation with its data sources and targets. These data sources and targets can be of any type (e.g., object-oriented, relational) or granularity (e.g., class, attribute, table, column). They can be persistent (e.g., stored in a relational database) or transient. 2. Accommodate both "black box" and "white box" transformations. In the case of "black box" transformations, data sources and targets are related to a transformation and to each other at a coarse-grain level. We know the data sources and targets are related through the transformation, but we donÂ’t know how a specific piece of a data source is related to a specific piece of a data target. In the case of "white box" transformations, however, data sources and targets are related to a transformation and to each other at a fine-grain level. We know exactly how a specific piece of a data source is related to a specific piece of a data target through a specific part of the transformation. 3. Allow grouping of transformations into logical units. At the functional level, a logical unit defines a single unit of work, within which all transformations must be executed and completed together. At the execution level, logical units can be used to define the execution grouping and sequencing (either explicitly through precedence constraints or implicitly through data dependencies). A key consideration here is that both parallel and sequential executions (or a combination of both) can be accommodated. The Transformation package assumes the existence of the following packages that represent types of potential data sources or targets: ObjectModel (object-oriented), Relational, Record, Multidimensional, XML, OLAP, and Data Mining. The Transformation package is an integral part of the following packages: OLAP, Data Mining, Warehouse Process, and Warehouse Operation. In particular, the Transformation and Warehouse Process packages together provide metamodel constructs that facilitate scheduling and execution in data warehousing, and the Transformation and Warehouse Operation packages together provide metamodel constructs that enable data lineage in data warehousing. This section provides a description of the main features of the Transformation package, as illustrated in Figure 13-1 (see specification document for figure). A transformation transforms a set of source objects into a set of target objects. The elements of a data object set can be any ObjectModel model elements, but typically are tables, columns, or model elements that represent transient, in memory, objects. Data object sets can be both sources and targets for different transformations. In particular, a given data object set can be the target of one transformation and the source of one or more transformations within the same logical unit. This is often the case with transformation that produce and consume temporary objects. Transformations allow a wide range of types (and granularity) to be defined for their data sources and targets. For example, the source type of a transformation can be an XML schema while the target type is a column, if the transformation deals with storing an XML document in a column of a relational database. More typically, the source types of a transformation are classes and attributes while the target types are tables and columns, or vice versa, if the transformation deals with converting object data into relational data, or vice versa. Existing programs, queries, or rules (in fact, any ObjectModel operations) can be used to perform a transformation by associating them with the transformation using the transformation use dependency. Transformations can be grouped into logical units. At the functional level, they are grouped into transformation tasks, each of which defines a set of transformations that must be executed and completed together - a logical unit of work. At the execution level, transformation steps are used to coordinate the flow of control between transformation tasks, with each transformation step executing a single transformation task. The transformation steps are further grouped into transformation activities. Within each transformation activity, the execution sequence of its transformation steps are defined either explicitly by using the step precedence dependency or precedence constraint, or implicitly through data dependency. There are certain "white-box" transformations which are commonly used and which can relate data sources and targets to a transformation and to each other at a detailed level. These transformations are convenient to use and they provide data lineage at a fine-grain level. One such transformation is the transformation map which consists of a set of classifier maps that in turn consists of a set of feature maps or classifier-feature maps. The other is the transformation tree, which represents a transformation as an unary or binary expression tree. For an example usage of the transformation map, please see Figure 13-4. The Transformation package depends on the following packages: omg.org::CWM::ObjectModel::Behavioral omg.org::CWM::ObjectModel::Core omg.org::CWM::Foundation::Expressions omg.org::CWM::Foundation::SoftwareDeployment The CWM uses packages to control complexity and create groupings of logically interrelated classes and associations. The Transformation package is one such package. Within the Transformation package itself, however, the definition of subpackages is purposefully left out to reduce the length and complexity of the fully qualified names of Transformation classes and associations. There are, however, several groupings of classes and associations that form related sets of functionality within the Transformation package. Although separate subpackages have not been created for these functional areas, their identification improves the understandability of the Transformation package. The Transformation package contains metamodel elements that support the following functions: 1. Transformation and data lineage. These classes and associations deal with transformations and their sources, targets, constraints, and operations. 2. Transformation grouping and execution. These classes and associations deal with grouping of transformations to form logical units and to define execution sequences. 3. Specialized transformations. These classes and associations define specialized, "white box", transformations that are commonly used in data warehousing. The specific Transformation classes and associations supporting each functional area are delineated in Table 13-1 (see specification document for table). The metamodel diagram for the Transformation package is split into four parts. The first two diagrams show the Transformation classes and associations, while the last two show the inheritance hierarchy. 13.5 OCL Representation of Transformation Constraints [C-1] The preceding step and succeeding step of StepPrecedence must not be the same. context StepPrecedence inv: self.precedingStep->forAll( p | self.succeedingStep->forAll( q | p <> q ) ) [C-2] A TransformationTask may not be its own inverse task. Identifies the Transformation context TransformationTask inv: self.inverseTask->forAll( p | p <> self ) [C-3] A TransformationTask may not be its own original task. context TransformationTask inv: self.originalTask->forAll( p | p <> self ) [C-4] The ClassifierMapToCFMap association is derived from the Namespace-ModelElement association. All ownedElement ends of the association must be ClassifierFeatureMaps. context ClassifierMapToCFMap inv Namespace-ModelElement.allInstances.select( ownedElement.oclIsKindOf( ClassifierFeatureMap ) ) [C-5] The ClassifierMapToFeatureMap association is derived from the Namespace-ModelElement association. All ownedElement ends of the association must be FeatureMaps. context ClassifierMapToFeatureMap inv Namespace-ModelElement.allInstances.select( ownedElement.oclIsKindOf( FeatureMap ) ) CWMTFM org.omg.cwm.analysis TransformationModule org.omg.java.cwm.analysis This represents a transformation from a set of sources to a set of targets. If a model already exists for the object that performs the Transformation, then the model can be related to the Transformation via a TransformationUse dependency. This represents a set of Transformations that must be executed together as a single task (logical unit). A TransformationTask may have an inverse task. A transformation task that maps a source set "A" into a target set "B" can be reversed by the inverse transformation task that maps "B" into "A". This represents the usage of a TransformationTask in a TransformationActivity. A TransformationStep relates to one TransformationTask. TransformationSteps are used to coordinate the flow of control between their TransformationTasks. Ordering of the TransformationSteps are defined using the PrecedenceConstrainedBy dependency. This represents a transformation activity. Each TransformationActivity consists of a set of TransformationSteps. tfm_ This association relates a ClassifierMap to its FeatureMaps. This association is derived from the Namespace-ModelElement association. All ownedElement ends of the association must be FeatureMaps. [C-5] This association relates a ClassifierMap to its ClassifierFeatureMaps. This association is derived from the Namespace-ModelElement association. All ownedElement ends of the association must be ClassifierFeatureMaps. [C-4] Online Analytical Processing (OLAP) is a class of analytic application software that exposes business data in a multidimensional format. This multidimensional format usually includes the consolidation of data drawn from multiple and diverse information sources. Unlike more traditionally structured representations (e.g., the tabular format of a relational database), the multidimensional orientation is a more natural expression of the way business enterprises view their strategic data. For example, an analyst might use an OLAP application to examine total sales revenue by product and geographic region over time, or, perhaps, compare sales margins for the same fiscal periods of two consecutive years. The ultimate objective of OLAP is the efficient construction of analytical models that transform raw business data into strategic business insight. There are many ways to implement OLAP. Most OLAP systems are constructed using OLAP server tools that enable logical OLAP structures to be built on top of a variety of physical database systems, such as relational or native multidimensional databases. The following features are generally found in most OLAP systems: Multidimensional representation of business data. Upward consolidation of multidimensional data in a hierarchical manner, possibly with the application of specialized processing rules. The ability to navigate a hierarchy from a consolidated value to the lower level values forming it. Support for time-series analysis; i.e., OLAP users are generally concerned with data and consolidations at specific points in time -- By date, week, quarter, etc. Support for modeling and scenario analysis -- A user should be able to apply arbitrary "what-if" analyses to a result set without affecting the stored information. Consistent response times, regardless of how queries are formulated -- This is critical for effective analysis and modeling. OLAP applications integrate well into the data warehousing environment, because a data warehouse provides relatively clean and stable data stores to drive the OLAP application. These data stores are usually maintained in relational tables that can be read directly by OLAP tools or loaded into OLAP servers. These relational tables are often structured in a manner that reveals the inherent dimensionality of the data (such as the ubiquitous Star and Snowflake schemas). Also, the data transformation and mapping services provided by a data warehouse can be used to supply OLAP systems with both metadata and data. Transformation-related metadata can be used to track the lineage of consolidated OLAP data back to its various sources. The primary objectives of the CWM OLAP package are: Define a metamodel of essential OLAP concepts common to most OLAP systems. Provide a facility whereby instances of the OLAP metamodel are mapped to deployment-capable structures (i.e., models of physical data resources, such as the CWM Relational and Multidimensional packages). Ensure that navigation through the logical OLAP model hierarchy and its various resource models is always performed in a uniform manner (i.e., by defining a standard usage of the CWM Transformation package as a means of implementing these mappings). Leverage services provided by other CWM packages, where appropriate (e.g., use the CWM Foundation package to supply a standard representation of expressions). The OLAP package depends on the following packages: org.omg::CWM::ObjectModel::Core org.omg::CWM::Foundation::Expressions org.omg::CWM::Analysis::Transformation The major classes and associations of the OLAP metamodel are shown in Figure 14-1. Schema is the logical container of all elements comprising an OLAP model. It is the root element of the model hierarchy and marks the entry point for navigating OLAP models. A Schema contains Dimensions and Cubes. A Dimension is an ordinate within a multidimensional structure and consists of a list of unique values (i.e., members) that share a common semantic meaning within the domain being modeled. Each member designates a unique position along its ordinate. A Cube is a collection of analytic values (i.e., measures) that share the same dimensionality. This dimensionality is specified by a set of unique Dimensions from the Schema. Each unique combination of members in the Cartesian product of the CubeÂ’s Dimensions identifies precisely one data cell within a multidimensional structure. CubeDimensionAssociation relates a Cube to its defining Dimensions. Features relevant to Cube-Dimension relationships (e.g., calcHierarchy) are exposed by this class. A Dimension has zero or more Hierarchies. A Hierarchy is an organizational structure that describes a traversal pattern through a Dimension, based on parent/child relationships between members of a Dimension. Hierarchies are used to define both navigational and consolidation/computational paths through the Dimension (i.e., a value associated with a child member is aggregated by one or more parents). For example, a Time Dimension with a base periodicity of days might have a Hierarchy specifying the consolidation of days into weeks, weeks into months, months into quarters, and quarters into years. A specific Hierarchy may be designated as the default Hierarchy for display purposes (e.g., a user interface that displays the Dimension as a hierarchical tree of members). CubeDimensionAssociation can also identify a particular Hierarchy as the default Hierarchy for consolidation calculations performed on the Cube. MemberSelection models mechanisms capable of partitioning a DimensionÂ’s collection of members. For example, consider a Geography Dimension with members representing cities, states, and regions. An OLAP client interested specifically in cities might define an instance of MemberSelection that extracts the city members. CubeRegion models a sub-unit of a Cube that is of the same dimensionality as the Cube itself. Each "dimension" of a CubeRegion is represented by a MemberSelection of the corresponding Dimension of the Cube. Each MemberSelection may define some subset of its DimensionÂ’s members. CubeRegions are used to implement Cubes. A Cube may be realized by a set of CubeRegions that map portions of the logical Cube to physical data sources. The MemberSelections defining CubeRegions can also be grouped together via MemberSelectionGroups, enabling the definition of CubeRegions with specific semantics. For example, one can specify a CubeRegion containing only the "input level" data cells of a Cube. A CubeRegion may own any number of CubeDeployments. CubeDeployment is a metaclass that represents an implementation strategy for a multidimensional structure. The ordering of the CubeDeployment classes may optionally be given some implementation-specific meaning (e.g., desired order of selection of several possible deployment strategies, based on optimization considerations). The OLAP metamodel defines two special types of Dimension: Time and Measure. A Time Dimension provides a means of representing time-series data within a multidimensional structure. The members of a Time Dimension usually define some base periodicity (e.g., days of the week). The implementation of a Time Dimension might provide support for advanced "time-intelligent" functionality, such as the ability to automatically convert between different periodicities and calendars. The members of a Measure Dimension describe the meaning of the analytic values stored in each data cell of a multidimensional structure. For example, an OLAP application may define Sales, Quantity and Weight as its measures. In this case, each data cell within the Cube stores three values, with each value corresponding to one of the three measures. A measure may have an associated data type. For example, Sales might be of a monetary type, Quantity an integer, and Weight a real number. The OLAP metamodel specifies two subclasses of Hierarchy: LevelBasedHierarchy and ValueBasedHierarchy. LevelBasedHierarchy describes hierarchical relationships between specific levels of a Dimension. LevelBasedHierarchy is used to model both "pure level" hierarchies (e.g., dimension-level tables) and "mixed" hierarchies (i.e., levels plus linked nodes). Dimensional levels are modeled by the Level class, a subclass of MemberSelection that partitions a DimensionÂ’s members into disjoint subsets, each representing a distinct level. For example, the Geography Dimension cited earlier contains members representing cities, states, and regions, such as "Stamford", "Connecticut", and "NorthEast". It might also contain a single member called "USA" representing all regions of the United States. Therefore, the Geography Dimension could have four Levels named "City", "State", 'Region", and "ALL", respectively. Each Level specifies the subset of members belonging to it: All cities belong to the "City" Level, all states belong to the "State" Level, all regions belong to the "Region" Level, and the single "USA" member belongs to the "ALL" Level. When used in the definition of a consolidation path, the meaning of "level" is quite clear: Members occupying a given Level consolidate into the next higher Level (e.g., City rolls up into State, State into Region, and Region into ALL). LevelBasedHierarchy contains an ordered collection of HierarchyLevelAssocations that defines the natural hierarchy of the Dimension. The ordering defines the hierarchical structure in top-down fashion (i.e., the "first" HierarchyLevelAssociation in the ordered collection represents the upper-most level of the dimensional hierarchy). A HierarchyLevelAssociation may own any number of DimensionDeployments. DimensionDeployment is a metaclass that represents an implementation strategy for hierarchical Dimensions. The ordering of the DimensionDeployment classes may optionally be given an implementation-specific meaning (e.g., desired order of selection of several possible deployment strategies, based on optimization considerations). A ValueBasedHierarchy defines a hierarchical ordering of members in which the concept of level has little or no significance. Instead, the topological structure of the hierarchy conveys meaning. ValueBasedHierarchies are often used to model situations where members are classified or ranked according to their distance from a common root member (e.g., an organizational chart of a corporation). In this case, each member of the hierarchy has some specific "metric" or "value" associated it with it. ValueBasedHierarchy can be used to model pure "linked node" hierarchies (e.g., asymmetric hierarchical graphs or parent-child tables). As with LevelBasedHierarchy, ValueBasedHierarchy also has an ordered collection of dimensionDeployments, where the ordering semantics are left to implementations to define. Figure 14-3 illustrates how classes of the OLAP metamodel inherit from the CWM Object Model. Two classes requiring further explanation are: Measure: A subclass of Attribute that describes the meaning of values stored in the data cells of a multidimensional structure. Different OLAP models often give different interpretations to the term "measure". In a relational Star Schema, individual measures might be represented by non-key columns of a Fact table (e.g., "Sales" and "Quantity" columns). In this case, measure may be an attribute of a Cube or CubeRegion that models the Fact table. On the other hand, measures can also be represented by members of a Measure Dimension. A Fact table supporting this representation has a single Measure column with column values consisting of the members "Sales" and "Quantity", and a single "value" column (i.e., an implicit data dimension) storing the corresponding measure values. A similar notion of Measure Dimension is used in modeling pure hypercube representations of multidimensional servers. Thus, the concept of measure can be represented either as a Dimenson or as an Attribute, depending on the type of OLAP system being modeled. Coded Level: A subclass of Level that assigns a unique encoding, or label, to each of its members. CodedLevel is not essential to the OLAP metamodel, but is provided as a helper class for certain applications that might benefit from the ability of OLAP systems to structure data hierarchically. For example, CodedLevel could be used to model systems of nomenclature or classification. The CWM OLAP metamodel describes logical models of OLAP systems, but does not directly specify how an OLAP system is physically deployed. Modeling the deployment of an OLAP system requires mapping instances of OLAP metaclasses to instances of other CWM metaclasses representing physical resources (e.g., mapping an OLAP Dimension to a Relational Table). This approach offers several advantages: The status of the OLAP metamodel as a conceptual model is preserved by this level of indirection. When using OLAP, a client may perceive to be working directly with OLAP objects, but the actual implementation of those objects is hidden from the client. For example, a client may view a member as a value of a Dimension, but whether that member value comes from a row of a relational table, or from a cell in a multidimensional database, is usually not obvious to the client. On the other hand, if a client needs to determine how a logical OLAP structure is physically realized, the metadata describing this mapping is fully available (assuming that the implementation allows the client to drill-down through the metadata). The possibility of defining mappings based on expressions means that the amount of metadata required to describe large models (e.g., Dimensions containing large collections of members) can be kept within reasonable bounds. It is generally more efficient to provide expressions that specify where large metadata sets reside, how to connect to them, and how to map their contents, rather than representing them directly as part of the metadata content. All of the OLAP metaclasses are potential candidates for such deployment mappings. In addition, some OLAP models may also define mappings between several OLAP metaclass instances, forming a natural hierarchy of logical objects (e.g., Dimension Attributes are mapped to Level Attributes which, in turn, are mapped to Table Columns). The CWM Transformation package is used as the primary means of describing these mappings. A modeler constructing an OLAP model based on CWM will generally define instances of the TransformationMap metaclass to link logical OLAP objects together, and to link those logical objects to other objects representing their physical data sources. StructureMap is a subclass of TransformationMap that models structure-oriented transformation mappings (i.e., member identity and hierarchical structure). This type of transformation mapping needs to be connected to the OLAP metamodel in a very specific way (according to Level and Hierarchy), so the StructureMap subclass is defined to make these associations explicit. Two specific usages of StructureMap are defined: ListOfValues, which maps attributes identifying members residing at a specific Level, or at a specific Level within a particular Hierarchy, and ImmediateParent, which maps attributes identifying the hierarchical parent(s) of the members. On the other hand, relatively simple TransformationMaps can be defined within any OLAP model to represent attribute-oriented transformations (e.g., mapping Dimension Attributes to Table Columns that store attribute values). ContentMap is a subclass of TransformationMap that models content-oriented transformaton mappings (i.e., cell data or measure values). For example, an instance of ContentMap might be used to map each of a CubeRegionÂ’s Measures to Columns of an underlying Fact Table. Note that, in either case (structural mapping or content mapping), the traversal patterns used by any CWM OLAP implementation are always the same, since both deployment mappings are based on the same usage of CWM TransformationMaps. In addition to representing structural mappings, instances of TransformationMap and its subclasses are also capable of storing implementation-dependent functions or procedures that yield the instance values associated with mapped model elements. For example, a "list of values" StructureMap might store an SQL statement such as "select memberName from Product where productFamily = Â’consumerElectronicsÂ’ ", as the value of its formula attribute. Figure 14-4 illustrates the CWM metaclasses and associations that describe deployment mappings between logical OLAP models and physical resource models. Note that it is possible to combine both Cube (content) and Dimension (structure) deployments together within the context of a single OLAP Schema (via the DeploymentGroup metaclass). Thus, an OLAP Schema can have several possible deployments that users may select based on implementation-specific considerations (e.g., physical optimizations). OCL Representation of OLAP Constraints [C-1] Ensure that the Dimensions defining a Cube are unique. context Cube inv: self.cubeDimensionAssociation->forAll( c1, c2 | c1 <> c2 implies c1.dimension <> c2.dimension ) [C-2] A Cube without CubeRegions cannot be mapped to a deployment structure (i.e., physical source of data). context Cube inv: self.cubeRegion->isEmpty implies self.isVirtual = true [C-3] If a calcHierarchy is defined, it must be a Hierarchy owned by the Dimension referenced by the CubeDimensionAssociation. context CubeDimensionAssociation inv: self.calcHierarchy->notEmpty implies self.calcHierarchy.dimension = self.dimension [C-4] A "fully realized" CubeRegion has no MemberSelectionGroups (and hence, no MemberSelections). context CubeRegion inv: self.isFullyRealized implies self.memberSelectionGroup->isEmpty [C-5] A CubeRegion defined by MemberSelections must have, for each Dimension of its owning Cube, a corresponding MemberSelection within each of its MemberSelectionGroups. context CubeRegion inv: self.memberSelectionGroup->notEmpty implies self.cube.cubeDimensionAssociation->forAll( d | self.memberSelectionGroup->forAll( g | g.memberSelection->exists( m | m.dimension = d.dimension ) ) ) [C-6] A CubeRegion defined by MemberSelections must have, within each MemberSelectionGroup, a MemberSelection corresponding to each Dimension of its owning Cube. context CubeRegion inv: self.memberSelectionGroup->notEmpty implies self.memberSelectionGroup->forAll( g | g.memberSelection->forAll( m | self.cube.cubeDimensionAssociation->exists( d | d.dimension = m.dimension ) ) ) [C-7] A Dimension may be a Time Dimension, a Measure Dimension, or neither, but never both types at the same time. context Dimension inv: not ( self.isTime and self.isMeasure ) [C-8] The default display Hierarchy (if defined) must be one of the Hierarchies owned by the Dimension. context Dimension inv: self.displayDefault->notEmpty implies self.hierarchy->includes( self.displayDefault ) [C-9] An instance of DimensionDeployment must be referenced exclusively by either a HierarchyLevelAssociation or a ValueBasedHierarchy. context DimensionDeployment inv: self.hierarchyLevelAssociation->isEmpty xor self.valueBasedHierarchy->isEmpty [C-10] Within a DimensionDeployment, an "immediate parent" StructureMap must always have an associated and distinct "list of values" StructureMap. context DimensionDeployment inv: self.immediateParent->notEmpty implies ( self.listOfValues->notEmpty and self.listOfValues <> self.immediateParent ) [C-11] A StructureMap referenced as a "list of values" StructureMap must not reside outside of the DimensionDeploymentÂ’s collection of StructureMaps. context DimensionDeployment inv: self.listOfValues->notEmpty implies self.structureMap->includes( self.listOfValues ) [C-12] A StructureMap referenced as an "immediate parent" StructureMap must not reside outside of the DimensionDeploymentÂ’s collection of StructureMaps. context DimensionDeployment inv: self.immediateParent->notEmpty implies self.structureMap->includes( self.immediateParent ) [C-13] The currentLevel of each HierarchyLevelAssociation must refer to a Level owned by the Dimension of the LevelBasedHierarchy containing the HierarchyLevelAssociation. context LevelBasedHierarchy inv: self.hierarchyLevelAssociation->notEmpty implies self.hierarchyLevelAssociation->forAll( h | self.dimension.memberSelection ->select( oclType = Olap::Level )->includes( h.currentLevel ) ) [C-14] No two HierarchyLevelAssociations may designate the same Level instance as their "current level". context LevelBasedHierarchy inv: self.hierarchyLevelAssociation->forAll( h1, h2 | h1 <> h2 implies h1.currentLevel <> h2.currentLevel ) CWMOLAP org.omg.cwm.analysis OlapModule org.omg.java.cwm.analysis A Cube is a collection of analytic values (i.e., measures) that share the same dimensionality. This dimensionality is specified by a set of unique Dimensions from the Schema. Each unique combination of members in the Cartesian product of the CubeÂ’s Dimensions identifies precisely one data cell within a multidimensional structure. Synonyms: Multidimensional Array, Hypercube, Hypervolume. CubeDimensionAssociation relates a Cube to the Dimensions that define it. Features relevant to Cube-Dimension relationships (e.g., calcHierarchy) are exposed by this class. CubeRegion models a sub-unit of a Cube of the same dimensionality as the Cube itself, with each Dimension optionally subsetted in its list of members. When mapped to its physical source, a CubeRegion contains data cells identified by the member combinations of the Cartesian product of the CubeRegion's associated Dimensions and Measures. The relative ordering of CubeDeployment classes optionally implies a desired order of selection of the CubeDeployments, based on implementation-specific considerations (e.g., optimized access of aggregate data). Synonyms: Sub-Cube, Partition, Slice, Region, Area. Misc. notes: 1. A CubeRegion is not a Cube, and a Cube is not a CubeRegion. 2. A Cube has a Measure and CubeRegion may have a corresponding measure (Measures are Attributes). 3. A Cube may or may not have CubeRegions. 4. If a Cube does not have a CubeRegion, then it's not physically mapped (it's virtual). All physical mapping is based on the CubeRegion , not the Cube. DeploymentGroup represents a logical grouping of model elements defining a single, complete deployment of an instance of Olap Schema (i.e., CubeDeployments and DimensionDeployments). The usage of DeploymentGroup is as follows: A user may specify a particular DeploymentGroup as the session-wide, default deployment for all metadata queries performed throughout the session. Alternatively, for queries involving some particular deployed object (e.g., a Cube or a Dimension), the user may be asked to choose from a list of deployments. This either becomes the default deployment for the remainder of the session, or the user may continue to be asked to specify a deployment for each subsequent query against deployed objects. A Dimension is an ordinate within a multidimensional structure, and consists of an ordered list of values (i.e., members) that share a common semantic meaning within the domain being modeled. Each member designates a unique position along its ordinate. Typical Dimensions are: Time, Product, Geography, Scenario (e.g., actual, budget, forecast), Measure (e.g., sales, quantity). DimensionDeployment represents a particular implementation strategy for the dimensional/hierarchical portions of an OLAP model. It does so by organizing a collection of StructureMaps, which in turn define a mapping to an implementation model. HierarchyLevelAssociation is a class that orders Levels within a LevelBasedHierarchy, and provides a means of mapping Level/Hierarchy-oriented Dimension attributes to one or more physical deployments. The relative ordering of DimensionDeployment classes optionally implies a desired order of selection of DimensionDeployments, based on implementation-specific considerations (e.g., optimized access of aggregate data). A LevelBasedHierarchy is a hierarchy that describes relationships between specific levels of a Dimension. LevelBasedHierarchy can be used to model to "pure level" hierarchies (e.g., dimension-level tables) and "mixed" hierarchies (i.e., levels + linked nodes). ValueBasedHierarchy is a subclass of Hierarchy that ranks Dimension members according to their relative distance from the root. Each member of a ValueBasedHierarchy has a specific "metric" or "value" associated with it. ValueBasedHierarchy is used to model pure "linked node" hierarchies (e.g., parent-child tables). StructureMap is a subclass of TransformationMap that maps Dimension attributes to their physical data sources. (Note: Multiple StructureMaps may be grouped together into single, cohesive unit via TransformationTask.) A HierarchyLevelAssociation may own any number of DimensionDeployments. The ordering of the DimensionDeployment classes may optionally be assigned an implementation-specific meaning (e.g., desired order of selection of multiple deployments, based on optimized access to aggregated data). A ValueBasedHierarchy may own any number of DimensionDeployments. The ordering of the DimensionDeployment classes may optionally be assigned an implementation-specific meaning (e.g., desired order of selection of multiple deployments, based on optimized access to aggregated data). MiningCoreModule org.omg.cwm.analysis CWMDM org.omg.java.cwm.analysis This object provides a mapping between a mining attribute (logical data) and a set of attributes in the input data (physical data). logicalAttribute is the mining attribute being mapped by this object. orderIdAttribute is used when ordering of attributes is required. In some cases, ordering of attributes is important (as in sequence analysis). In other cases, a sequence of an attribute is favored over having a set-valued attributes. AttributeAssignment can be reused among several tasks, but a MiningAttribute can be refered to by an AttributeAssignment within a task. This enumeration determines which attriute in the given data to select and map it to a set-valued logical attribute. The attributes that satisfy the given condition in this enumeration get selected. The usage attribute indicates if the MiningAttribute should be used by the model or not, according to the details specified in the UsageOption enumeration class. The default is "active". This suppresses discretization to be performed on the attribute being specified, if true. The default is false. umlAttribute A CategoricalAttributeProperties object is used to describe properties of a categorical attribute. It lists the specific categories that are recognized in the attribute, as well as a taxonomy, or CategorizationGraph, that organizes the categories into a hierarchy. This metadata may or may not be used by the underlying algorithm. It may be leveraged to determine if data being supplied as input to a mining operation is sufficiently similar to the data used to build the model. Maps a pair of attributes from two different sources, for example a table column and a MiningAttribute. In this example, the table column is represented by attribute. The attribute type indicates if the attribute is categorical, ordinal, numerical, or not specified. If either categoricalProperties or numericalProperties are specified, a constraint exists to ensure the attributeType value is consistent with these attributes. This attribute allows a MiningAttribute to be identified with a particular type even if no additional properties are specified. If ordinal, then the OrdinalAttributeProperties must be specified to indicate the ordering of the categories. A NumericalAttributeProperties object is used to describe properties of the numerical attribute. This metadata may or may not be used by the underlying algorithm. It may be leveraged to determine if data being supplied as input to a mining operation is sufficiently similar to the data used to build the model. This indicates whether the values of the attributes are cyclic, i.e., the next value of the ending value is the starting value. The default is false. A PhysicalData object specifies the layout of the physical data to be used for mining, and if appropriate, the roles the various data columns play, via subclassing. The data referenced by a physical data object can be used in many capacities: model building, scoring, lift computation, statistical analysis, etc. PhysicalData supports specification of any data definable through a Class or set of Attributes, e.g., files, tables, and star schema. This object provides a mapping where the input data is in transactional format. Each of the logical attributes ocurring in a pivoted table is mapped to three physical columns, presumably the same ones every time. If the data types don't match, the value column may be different in that case. Question: Seems that we need to have more than one logical attribute associated with this assignment. Constraint: The logicalAttribute must be set valued. This object is used when the input data is in tabular (2-D) form. The sets are represented by enumerating their elements based on the selection functions. For example, if the attribute selection function is "isOne" and the value selection function is "attribute", the we get: A B C D E F 1 0 0 1 0 0 = {A, D} 0 0 0 0 0 1 = {F} 0 0 0 0 0 0 = {} Each of the input attributes (A, B, C, D, E, and F) is a selector attribute in this object. It works best for a small number of members known a priori. In some cases, when the potential number of values is large, but it is also known that the set sizes are all small, e.g., less than 6, then we get the following: A B C D F X Y NULL NULL NULL = {X, Y} Z NULL NULL NULL NULL = {Z} NULL NULL NULL NULL NULL = {} In the above example, the attribute selection function is "isNotNull" and the value selection function is "value". Constraint: The logicalAttribute must be set valued. This object provides a mapping between a set-valued mining attribute and a set of attributes in the physical data. setIdAttribute is the set identifier of the set being mapped. memberAttribute represents a set of attributes being mapped to the set-valued mining attribute. vsf_ This represents a discrete value. A collection of Category instances defines the values that may or may not be annotated with a mining attribute. Constraint on value: Datatype must define equality operator. The optional attribute isNullCategory is set to true if the Category provided is the NULL category. If true, this invalidates any specification in the value attribute. A CategoryMatrix assigns numeric values to pairs of categories. It is either represented as a set of CategoryMatrixEntries or as a table. Type of matrix, 'diagonal', 'symmetric', or 'any'. If diagonal, then all values outside the diagonal are 0. If symmetric then value(i,j)=value(j,i). Value of a cell. It overwrites any default value in CategoryMatrix. For Cost matrix, value is intended to be a double. For ConfusionMatrix, the value can be either a "count" which is an integer value, or a "percentage" which is a double value. This is up to the implementation. Table with three columns holding the definition of a category matrix. Tabular representation of a CategoryMatrix. A category matrix consists of exactly one table. The table has three row, column and value of the entry. A CategorizationGraph supports the specification of taxonomy or category hierarchy as required by data mining in the form of a directed acyclic graph. It enables two representations: 1) explicit specification of the graph through the referenced node class, and 2) referencing MiningData with specific attributes (columns) that store the data in tabular form. A CategorizationGraph can contain multiple "root" nodes, in a sense being a single representation for several possibly strict hierarchies. Constraint to have either the MiningData instances (CategoryMapTable) OR the java object instances (CategoryMap). Note: This is a "graph" as opposed to a "hierarchy" because it can have multiple roots, i.e. hierarchies in the same object. mp_ MiningDataModule A mining algorithm settings object captures the parameters associated with a particular algorithm. It allows a knowledgeable user to fine tune algorithm parameters. Generally, not all parameters must be specified, however, those specified are taken into account by the underlying data mining system. Separating mining algorithm from mining function provides a natural and convenient separation for those users experienced with data mining algorithms and those only familiar with mining functions. A MiningFunctionSettings object captures the high level specification input for building a data mining model. The intent of mining function settings, is to allow a user to specify the type of result desired without having to specify a particular algorithm. Although mining function settings allow for the specification of algorithm, if this is omitted, the underlying data mining system is responsible for selecting the algorithm based on basic user-provided parameters. Subclasses throw exceptions if invalid algorithm-function pairs are supplied. The desiredExecutionTime attribute indicates the maximum execution time (in minutes) allowed for model building. If NULL, the algrotihm determines for how long the model will build. This is to serve as a hint to the algorithm to adjust model building to meet the time constraint. Vendor implementations may support this to varying degrees, e.g., terminate model build if exceeds this limit, intelligently adjust algorithm parameters to meet this constraint, or dynamically distribute or parallelize the operation. MiningFunctionSettingsModule A MiningModel holds the metadata of the result of a mining (training) run. This information is sufficient to determine whether a model can be applied to given data. Data mining function (as opposed to algorithm), e.g. classification or clustering. The following function names are predefined: attributeImportance associationRules classification regression clustering Specific implementation of the data mining function, e.g. CART decision tree or SOM clustering. The following algorithm names are predefined (their functions in parentheses): decisionTree (classification, regression) neuralNetwork (classification, regression) naiveBayes (classification) selfOrganizingMap (clusteirng) kMeans (clustering) competitiveLearning A SignatureAttribute object describes the input expected to a model. This is automatically produced as part of the model. It indicates not only the basic Attribute properties, but also how outliers and missing values were handled for model build. This is potentially duplicate information from the MiningFunctionSettings, but must be provided since MiningFunctionSettings are optional. If an attribute was normalized or discretized automatically by the Data Mining System, the specific details are provided in the SignatureAttribute object. The user is not expected to use this information to preprocess the data in any way. The Data Mining System uses this information to automatically preprocess data, if required. The usage intended for this attribute. A model signature consists only of 'active' and 'supplemental' attributes. 'Inactive' attributes are filtered out as they do not contribute to the model. Note that 'supplemental' attributes do not contribute to model apply. MiningModelModule A MiningResult holds the metadata of the result of a mining run other than training that results in a model. It includes apply, test, and compute lift operations. MiningResultModule This object describes an entity of apply output. It is usually stored in a destination attribute. The destination attribute is specified by an AttributeAssignment object. If Transactional output, then ApplyOutputItem does not have a destination attribute. Instead, the (name) entry for the attrNameAttribute is held in 'name' inherited from ModelElement This describes the ouput Specification for a MiningApplyTask. It contains a set of attributes (represented as ApplyOutputItem objects) holding the output information. These attributes can hold the score or other computed information, or else be copied from input columns for reference. MiningTaskModule EntryPointModule ClusteringModule org.omg.cwm.analysis CWMDM org.omg.java.cwm.analysis Per ClusteringModel, there is one aggregation function: depending on the attribute type. The aggregated value is optimal if it is 0 (for distance measure) or greater values indicate optimal fit (for simiarity measure). In the definition of functions, Wi is the field weight in the attribute, and Xi and Yi are values. When two records are compared, then either the distance or similarity is of interest. In both cases the measures can be compouted by a combination of an "inner" function and an "outer" function. The inner function compares two single field values and the outer function computes an aggregation over all fields. Each field has a comparison function, this is either defined as a default in ClusteringModel or it can be defined per attribute. A ClusteringAttributeUsage is a subclass of AttributeUsage to support attribute usages that are specific to clustering algorithms. AssociationRulesModule org.omg.cwm.analysis CWMDM org.omg.java.cwm.analysis SupervisedModule org.omg.cwm.analysis CWMDM org.omg.java.cwm.analysis ClassificationModule org.omg.cwm.analysis CWMDM org.omg.java.cwm.analysis As a subclass of AttributeUsage, CategoricalAttributeUsage provides additional specification for categorical attributes only, in particular, a set of the positive categories. Positive categories are provided here since different models may choose different postive categories, hence it is not a characteristic of the data. A ClassificationFunctionSettings object is a subclass of SupervisedFunctionSettings that supports features unique to the classification mining function and corresponding algorithms, specifically costMatrix. The costMatrix must be associated with the target MiningAttribute. This represents a set of prior probabilities of the categories in a mining attribute. Mostly applies to a target MiningAttribute used for classification. The sum of the probabilities in all priorsEntries must not exceed 1. This represents the probability of the targetValue in the original data. The value must be in [0,1] ApproximationModule org.omg.cwm.analysis CWMDM org.omg.java.cwm.analysis An ApproximationFunctionSettings is a subclass of SupervisedFunctionSettings that supports features that are unique to approximate numerical values. This originally was named "RegressionFunctionSettings", however, this implies a restriction on the type of algorithms that can be applied to solve the problem of approximation, or curve fitting. This represents a task to check the quality of a regression model. A comparison of mean predicted values and mean actual values can be done and a number of numerical error measures can be computed. NULL values mean that the model did not compute the value. AttributeImportanceModule org.omg.cwm.analysis CWMDM org.omg.java.cwm.analysis The CWM Information Visualization metamodel defines metadata supporting the problem domain of "information publishing" or, more generally, "information visualization". Within the data warehousing environment, data is collected from numerous, diverse sources and transformed into a unified representation that facilitates the analysis of data for purposes of gaining business insight. Robust and flexible information visualization tools are key to the effective analysis of this information. Information visualization tools must be capable of understanding and preserving the "logical structure" of data warehouse information, while enabling the user to perform any number of "rendering transformations" on information content (e.g., displaying the same query result set in several different formats, such as a printed report, Web page, pie chart, bar graph, etc.). Since information visualization is a very broad problem domain, with a diverse set of possible solutions and many evolving standards, the CWM Information Visualization metamodel defines very generic, container-like metadata constructs that either contain or reference more complex visualization mechanisms at the M1-level. These metadata structures are intended to support the minimal metadata required to interchange more complex M1 models of visualization mechanisms. The Information Visualization package depends on the following packages: org.omg.cwm.objectmodel.core org.omg.cwm.foundation.expressions RenderedObject is the logical proxy for an arbitrary ModelElement that is to be rendered via some rendering transformation or process. A RenderedObject may be composed of an arbitrary number of other RenderedObjects (i.e., components), and may have topological relationships to still other RenderedObjects. The formula attribute allows for the specification of any implementation-dependent expression that completes the definition of a RenderedObject. For example, the formula might specify the position of the RenderedObject within a two-dimensional grid, or in relation to one of its neighbors; e.g., formula = "neighbor(x, y) + (delta-x, delta-y)". A RenderedObject generally references one or more Renderings that specify how the enderedObject is actually presented. One of these associated Renderings may optionally be designated as a default Rendering. A Rendering is semantically equivalent to a transformation, in that it transforms a source RenderedObject to some target "displayed" (or otherwise "presented" object -- e.g., a displayed image or an audio clip) . An instance of Rendering is fully specified via its formula attribute, which, like RenderedObject, contains an implementation-dependent expression. Thus, a RenderedObject may be viewed as the "logical description" of an object to be rendered, independently of how it is actually presented by any of its associated Renderings, and Renderings may be viewed as transformations that control the presentation of the RenderedObject while preserving its logical structure. Note that a RenderedObject may be the target of a complex transformation (i.e., utilizing the CWM Transformation package). For example, an N-dimensional OLAP cube might be transformed into an equivalent, two-dimensional, composite RenderedObject, with several dimensions mapped to row and column edges, respectively, and all other dimensions constrained to single member values. Several Renderings may then be defined and associated with the resultant RenderedObject, mapping the two-dimensional logical structure to the surface of a display screen in various different formats (e.g., spreadsheet, pie chart, bar graph, etc.). Possible types of Renderings include: Screen, paper, voice, Web, HTML documents, XML/XSL, languages based on extensions to XML, SVG, visual objects, responses to keying (e.g., keying interception plus rules), etc. XSLRendering represents a useful subtype of Rendering thatÂ’s based on XSL (e.g., this subtypeÂ’s formula might contain a procedure that uses XSL to create an HTML document). Finally, RenderedObjectSet represents a simple container of both logical RenderedObjects and available Renderings. The inheritance of the Information Visualization metamodel from the Object Model is shown in Fig. 16-2. OCL Representation of Information Visualization Constraints [C-1] The set of Renderings includes the default Rendering. context RenderedObject inv: self.defaultRendering->notEmpty implies self.rendering->includes( self.defaultRendering ) [C-2] A RenderedObject may not reference itself as a Neighbor nor as a Component. context RenderedObject inv: self.neighbor->excludes( self ) inv: self.component->excludes( self ) [C-3] A RenderedObject may not reference one of its Neighbors as a Component (and vice versa). context RenderedObject inv: (self.neighbor->notEmpty and self.component->notEmpty) implies self.neighbor->intersection( self.component )->isEmpty The transitive closure of Neighbors of an instance of RenderedObject must not include the RenderedObject instance. The transitive closure of Components of an instance of RenderedObject must not include the RenderedObject instance. org.omg.cwm.analysis CWMIV InformationVisualizationModule org.omg.java.cwm.analysis RenderedObject serves as a logical "proxy" for an arbitrary ModelElement that is to be rendered. CwmRenderedObjectSet Rendering is a specification of how an associated RenderedObject is to be "rendered" in some medium. This usually consists of a projection of an object of arbitrary dimensionality onto a 2-dimensional surface, but it may also include non-physical representations as well (such as audio). A Rendering is semantically equivalent to a Transformation, in that it transforms a source RenderedObject to some target "presented" object. An instance of Rendering is fully specified via its formula attribute, which contains an implementation-dependent expression that defines the transformation and tracks transformation lineage. Possible types of instances of Rendering: Screen, Paper, Voice, Web, HTML Document, XML/XSL, languages based on extensions to XML, SVG, Visual objects, responses to keying (keying interception plus rules), etc. Business users of data warehouses need to have a good understanding of what information and tools exist in a data warehouse. They need to understand what the information means from a business perspective, how it is derived, from what data resources it is derived, and what analysis and reporting tools exist for manipulating and reporting the information. They may also need to subscribe to analysis and reporting tools, and have them run with results delivered to them on a regular basis. The BusinessNomenclature package contains classes and associations that can be used to represent business metadata. Easy access to this business metadata enables business users to exploit the value of the information in a data warehouse. It can also aid technical users in certain tasks. An example is the use of common business terms and concepts for discussing information requirements with business users. Another example is accessing business intelligence tools for analyzing the impact of warehouse design changes. The scope of the BusinessNomenclature package is restricted to the domain of data warehousing and business intelligence. This section provides a description of the main features of the BusinessNomenclature package. The BusinessNomenclature package provides two main constructs to represent business terms and concepts and related semantics: Taxonomy is a collection of concepts that provide the context for the meaning of a particular term. Glossary is a collection of terms and various related forms of the term. A taxonomy is a collection of concepts. Concepts represent semantic information and relationships. Concepts are identified by terms, which in turn are manifested by a word or phrase. More than one term may describe the same concept and a given term may describe more than one concept. A glossary is a collection of terms that are related through explicit or implicit relationships. Terms may be preferred (the term best representing its concept) and thus represent the vocabulary of a business domain or user. Terms may be synonyms and point at the preferred term. A preferred term and its synonyms represent the fact that several terms describe the same concept although with different shades of meaning. Terms may be arranged into a hierarchy of more generic and more specific elements. This relationship allows substituting a narrower term, such as "USA", for a wider term, such as "country". The BusinessNomenclature package depends on the following packages: omg.org::CWM::ObjectModel::Core The metamodel diagram for the BusinessNomenclature package is split into two parts. The first diagram shows the BusinessNomenclature classes and associations, while the second shows the inheritance hierarchy. OCL Representation of Business Nomenclature Constraints [C-1] A Concept may not relate to itself. context Concept inv: self.relatedConcept->forAll ( p | p <> self ) [C-2] The parent of a Glossary must be a Glossary. context Glossary inv: self.parent.oclIsKindOf( Glossary ) [C-3] The child of a Glossary must be a Glossary. context Glossary inv: self.child->forAll( p | p.oclIsKindOf( Glossary ) ) [C-4] The parent of a Taxonomy must be a Taxonomy. context Taxonomy inv: self.parent.oclIsKindOf( Taxonomy ) [C-5] The child of a Taxonomy must be a Taxonomy. context Taxonomy inv: self.child->forAll( p | p.oclIsKindOf( Taxonomy ) ) [C-6] A Term may not relate to itself. context Term inv: self.relatedTerm->forAll ( p | p <> self ) [C-7] A VocabularyElement may not relate to itself. context Vocabulary inv: self.relatedElement->forAll ( p | p <> self ) [C-8] The RelatedConcepts association is derived from the RelatedVocabularyElements association. All ends of the RelatedConcepts association must be Concepts. context RelatedConcepts inv: RelatedVocabularyElements.allInstances.select( element.oclIsKindOf( Concept ) and relatedElement.oclIsKindOf( Concept ) ) [C-9] The RelatedTerms association is derived from the RelatedVocabularyElements association. All ends of the RelatedTerms association must beTerms. context RelatedTerms inv: RelatedVocabularyElements.allInstances.select( element.oclIsKindOf( Term ) and relatedElement.oclIsKindOf( Term ) ) CWMBUS org.omg.cwm.analysis BusinessNomenclatureModule org.omg.java.cwm.analysis This represents a business idea or notion. Concepts are represented by Terms. Users use Terms that are familiar to them in their business environment to refer to Concepts. This represents words or phrases used by business users to refer to Concepts. A Term has a definition in a specific context. The context is provided by the referenced Concept that describes the underlying semantics. This association relates a Concept to its related Concepts. This association is derived from the RelatedVocabularyElements association. All ends of the association must be Concepts. [C-8] This association relates a Term to its related Terms. This association is derived from the RelatedVocabularyElements association. All ends of the association must be Terms.[C-9] The Warehouse Process package documents the process flows used to execute transformations. These process flows may be documented at the level of a complete TransformationActivity or its individual TransformationSteps. A WarehouseProcess object associates a transformation with a set of events which will be used to trigger the execution of the transformation. The Warehouse Process package depends on the following packages: org.omg::CWM::ObjectModel::Core org.omg::CWM::ObjectModel::Behavioral org.omg::CWM::Analysis::Transformation A WarehouseProcess object represents the processing of a transformation. It is instantiated as one of its subtypes WarehouseActivity or WarehouseStep, depending on whether it represents the processing of a TransformationActivity or a Transformation Step. A WarehouseProcess may be associated with one or more WarehouseEvents, each identifying events that cause the processing to be initiated. It may also be associated with one or more internal events that will be triggered when processing terminates. A ProcessPackage may be used to group together related WarehouseActivities. WarehouseEvents are divided into three categories: scheduled, external and internal. Scheduled events can either be defined as a point in time (each Wednesday at 2 pm) or be defined by intervals (every five minutes). A point in time event can be defined as a custom calendar which contains a set of calendar dates. This allows a series of dates to be reused across several WarehouseProcesses. External events are triggered by something happening outside the data warehouse, for example by a batch process which is not described as a WarehouseProcess. Internal events are triggered by the termination of a WarehouseProcess. They can be either retry events or cascade events. Retry events normally trigger a rerun of the same WarehouseProcess, whereas cascade events normally trigger a different WarehouseProcess. An internal event may define a condition that determines whether or not the event is triggered. This condition can use details of the execution of the triggering WarehouseProcess recorded in the relevant ActivityExecution and StepExecution objects. OCL Representation of Warehouse Process Constraints [C-1] month must be specified when recurringType is everyYear. context RecurringPointInTimeEvent inv: self.recurringType=everyYear implies self.month->notEmpty [C-2] month must be between 1 and 12 (inclusive) when specified. context RecurringPointInTimeEvent inv: self.month->notEmpty implies 1 <= self.month <= 12 [C-3] dayOfMonth must be specified when recurringType is everyYear or everyMonth. context RecurringPointInTimeEvent inv: self.recurringType=everyYear or self.recurringType=everyMonth implies self.dayOfMonth->notEmpty [C-4] dayOfMonth must be between 1 and 31 (inclusive) when specified. context RecurringPointInTimeEvent inv: self.dayOfMonth->notEmpty implies 1 <= self.dayOfMonth <= 31 [C-5] dayOfWeek must be specified when recurringType is everyWeek. context RecurringPointInTimeEvent inv: self.recurringType=everyWeek implies self.dayOfWeek->notEmpty [C-6] hour must be specified when recurringType is everyYear or everyMonth or everyWeek or everyDay. context RecurringPointInTimeEvent inv: self.recurringType=everyYear or self.recurringType=everyMonth or self.recurringType=everyWeek or self.recurringType=everyDay implies self.hour->notEmpty [C-7] hour must be between 0 and 23 (inclusive) when specified. context RecurringPointInTimeEvent inv: self.hour->notEmpty implies 0 <= hour <= 23 [C-8] minute must be specified when recurringType is not everyMinute. context RecurringPointInTimeEvent inv: self.recurringType<>everyMinute implies self.minute->notEmpty [C-9] minute must be between 0 and 59 (inclusive) when specified. context RecurringPointInTimeEvent inv: self.minute->notEmpty implies 0 <= self.minute <= 59 [C-10] second must be between 0 and 59 (inclusive). context RecurringPointInTimeEvent inv: 0 <= self.second <= 59 CWMWHP org.omg.cwm.management WarehouseProcessModule org.omg.java.cwm.management A virtual class to refer to any Event. A WarehouseEvent (or its derivations) represents what triggers the running of a WarehouseProcess. An event can be initiated by a clock, by an external trigger, or by an internal trigger (the conclusion of some WarehouseProcess). A PointInTime event is triggered at a fixed time, independently of any external context. The triggering time can be either defined functionally (as in the RecurringPointInTimeEvent extension of this class), or by an explicit list of times (CustomCalendarEvent). An IntervalEvent controls a continuous run of a WarehouseProcess. The Warehouse Process will run, then wait for the duration specified in the event, then run again. An IntervalEvent is not affected by the result of the WarehouseProcess. Indicates the length of time (in seconds) to wait after a run of the WarehouseProcess before triggering the next one. An ExternalEvent allows the description of the triggering of a WarehouseProcess by a task which is not described in the model. This is merely a place holder. The actual behavior and the connection with the external trigger is left to the implementation of the scheduler. An event which may be triggered, depending on whether or not a condition is satisfied, by the conclusion of one or more WarehouseProcess runs. There are two types of InternalEvents, depending whether the event triggers a series of different WarehouseProcesses, or whether the event triggers the same WarehouseProcess in an attempt to retry a failed run. Indicates what condition the triggering WarehouseProcess run must meet to be considered (success, failure, warnings, etc.). How the condition is expressed, and how the result of a Transform is generated is left to the implementation of the scheduler and the transformation, respectively. Indicates that a WarehouseProcess should be retried upon failure. This type of event is used for example when a WarehouseProcess relies on sources with uncertain availability (connection or uptime). In general, the triggering WarehouseProcess and the triggered WarehouseProcess are the same, and only one WarehouseProcess is involved. But this is not an imposed limitation. It is left to the schedulers to decide on the implementation behavior for complex cases. Indicates which month of the year (from 1 to 12) an annual event is to be triggered. Indicates which day of the month (from 1 to 31) a monthly or annual event is to be triggered. For a monthly event, if the day of the month is greater than the number of days in the month, it is assumed that the scheduler will run the WarehouseProcess on the last day of the month. Indicates which day of the week a weekly schedule is running. Indicates at what hour (from 0 to 23) an annual, monthly, weekly, or daily event is being triggered. Indicates at what second (from 0 to 59) an event must be run. Applies to all events. A WarehouseProcess represents the processing of a transformation. It is instantiated as one of its subtypes WarehouseActivity or WarehouseStep, depending on whether it represents the processing of a TransformationActivity or a Transformation Step. A WarehouseProcess may be associated with one or more WarehouseEvents, each identifying events that cause the processing to be initiated. It may also be associated with one or more internal events that will be triggered when processing terminates. When a WarehouseProcess is a constant mapping (such as a Relational View of legacy data or a continuous data propagation process), this flag indicates that the mapping does not require to be run for the target to be up-to-date and in sync with the source. A WarehouseStep is a component of a WarehouseActivity. It represents the processing of an individual TransformationStep. It may be used to identify WarehouseEvents that trigger the processing of the TransformationStep and/or InternalEvents that are triggered by the conclusion of the processing of the TransformationStep. For example, a WarehouseStep may be used to document how a specific TransformationStep should be retried upon failure. A WarehouseActivity is a subtype of WarehouseProcess that represents the processing of a TransformationActivity. It may identify WarehouseEvents that trigger the processing of the TransformationActivity and InternalEvents that are triggered by the conclusion of this processing. It may contain a set of WarehouseSteps that define in more detail the processing of the individual TransformationSteps of the TransformationActivity. The Warehouse Operation package contains classes recording the day-to-day operation of the warehouse processes. The package covers three separate areas: Transformation Executions Measurements Change Requests Details of the most recent executions of transformations can be recorded, identifying when they ran and whether they completed successfully. This can be used to determine how complete and up-to-date specific information in the data warehouse is. An ActivityExecution represents an execution of a whole TransformationActivity, and a StepExecution object represents an execution of an individual TransformationStep. If a TransformationStep involves the use of an Operation , an associated StepExecution may reference a CallAction that records the actual arguments passed to the Operation. These classes allow the lineage of data in a data warehouse to be preserved, by recording when and how it was derived, and where it came from. Measurement objects allow metrics to be held for any ModelElement. For example, they may be used to hold actual, estimated or planned values for the size of a table. ChangeRequests allow details of proposed changes affecting any ModelElement to be recorded. They may also be used to keep a historical record of changes implemented or rejected. The Warehouse Operation package depends on the following packages: org.omg::CWM::ObjectModel::Core org.omg::CWM::ObjectModel::Behavioral org.omg::CWM::Analysis::Transformation Separate model diagrams are shown below for each of the three main areas supported by the package. OCL Representation of Warehouse Operation Constraints [C-1] A ChangeRequest instance must not apply to itself. context ChangeRequest inv: self.modelElement -> forAll (element | element <> self) [C-2] A completionDate may only be provided for a completed ChangeRequest. context ChangeRequest inv: self.completionDate->notEmpty implies self.completed [C-3] A Measurement instance must not apply to itself. context Measurement inv: self.modelElement <> self [C-4] If the TransformationExecution is not inProgress, the successful, status and endDate attributes must be present, and endDate must not be earlier than startDate. context TransformationExecution inv: self.inProgress=false implies (self.successful->notEmpty and self.status->notEmpty and self.endDate->notEmpty and self.endDate >= self.startDate) CWMWHO org.omg.cwm.management WarehouseOperationModule org.omg.java.cwm.management A Measurement object indicates the value of some attribute of an object. It can be the number of rows in a table, the number of pages in an index, the number of different values in a column, etc. The flexibility of this class allows for product specific extensions, without changing the model. Identifies how the value was computed. The following values have specific meanings: measure (measured value) estimate (estimated value) plan (planned value) minimum (minimum value) maximum (maximum value) average (average value) umlValue Indicates that no further action is required for this change request, i.e. it has either been implemented or been rejected. CWMComplete is a package that invokes all other CWM packages. It does this by listing all of the other CWM metamodel packages in declaration order in the uml2mof.clusteredImport property of the MOF tab. CWMComplete is included as a convenience for software that wants to generate the entire CWM package. It is non-normative, is not included in any normative CWM dtd file, and is not documented in either volume of the CWM specification. org.omg.cwm CWM CWMCompleteModule org.omg.java.cwm libxml-ruby-5.0.3/test/test_traversal.rb0000644000004100000410000000611514620142101020355 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestTranversal < Minitest::Test ROOT_NODES_LENGTH = 27 ROOT_ELEMENTS_LENGTH = 13 def setup filename = File.join(File.dirname(__FILE__), 'model/books.xml') @doc = LibXML::XML::Document.file(filename) end def teardown @doc = nil end def test_children # Includes text nodes and such assert_equal(ROOT_NODES_LENGTH, @doc.root.children.length) end def test_children_iteration # Includes text nodes and such nodes = @doc.root.children.inject([]) do |arr, node| arr << node arr end assert_equal(ROOT_NODES_LENGTH, nodes.length) end def test_no_children # Get a node with no children node = @doc.find_first('/catalog/book[@id="bk113"]/price') assert_equal(0, node.children.length) end def test_no_children_inner_xml # Get a node with no children node = @doc.find_first('/catalog/book[@id="bk113"]/price') assert_nil(node.inner_xml) end def test_each # Includes text nodes and such nodes = @doc.root.inject([]) do |arr, node| arr << node arr end assert_equal(ROOT_NODES_LENGTH, nodes.length) end def test_each_element # Includes text nodes and such nodes = [] @doc.root.each_element do |node| nodes << node end assert_equal(ROOT_ELEMENTS_LENGTH, nodes.length) end def test_next nodes = [] node = @doc.root.first while node nodes << node node = node.next end assert_equal(ROOT_NODES_LENGTH, nodes.length) end def test_next? first_node = @doc.root.first assert(first_node.next?) last_node = @doc.root.last assert(!last_node.next?) end def test_prev nodes = [] node = @doc.root.last while node nodes << node node = node.prev end assert_equal(ROOT_NODES_LENGTH, nodes.length) end def test_prev? first_node = @doc.root.first assert(!first_node.prev?) last_node = @doc.root.last assert(last_node.prev?) end def test_parent? assert(!@doc.parent?) assert(@doc.root.parent?) end def test_child? assert(@doc.child?) assert(!@doc.root.first.child?) end def test_next_prev_equivalence next_nodes = [] last_nodes = [] node = @doc.root.first while node next_nodes << node node = node.next end node = @doc.root.last while node last_nodes << node node = node.prev end assert_equal(next_nodes, last_nodes.reverse) end def test_next_children_equivalence next_nodes = [] node = @doc.root.first while node next_nodes << node node = node.next end assert_equal(@doc.root.children, next_nodes) end def test_doc_class assert_instance_of(LibXML::XML::Document, @doc) end def test_root_class assert_instance_of(LibXML::XML::Node, @doc.root) end end libxml-ruby-5.0.3/test/test_writer.rb0000644000004100000410000003715714620142101017700 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' require 'stringio' class TestWriter < Minitest::Test XSL_PREFIX = 'xsl' XSL_URI = 'http://www.w3.org/1999/XSL/Transform' def test_generic_failure writer = LibXML::XML::Writer.string writer.start_document assert(!writer.end_element) writer.end_document end def test_empty_doc writer = LibXML::XML::Writer.string document(writer) assert_equal(writer.result.strip!, '') writer = LibXML::XML::Writer.string document(writer, :encoding => LibXML::XML::Encoding::ISO_8859_1) assert_equal(writer.result.strip!, '') writer = LibXML::XML::Writer.string document(writer, :standalone => 1) assert_equal(writer.result.strip!, '') writer = LibXML::XML::Writer.string document(writer, :standalone => 1, :encoding => LibXML::XML::Encoding::ISO_8859_1, :foo => :bar) assert_equal(writer.result.strip!, '') end def test_file_encoding value = "François".encode(Encoding::UTF_8) File.open('test.xml', 'wb', encoding: 'UTF-8') do |file| writer = LibXML::XML::Writer::io(file) document(writer, encoding: LibXML::XML::Encoding::UTF_8) do writer.write_element('Name', value) end end end def test_io_encoding value = "François".encode(Encoding::UTF_8) expected = "\nFrançois".encode(Encoding::UTF_8) io = StringIO.new writer = LibXML::XML::Writer::io(io) document(writer, encoding: LibXML::XML::Encoding::UTF_8) do writer.write_element('Name', value) end assert_equal(expected, io.string.strip) end def test_single_root writer = LibXML::XML::Writer.string document(writer) do element writer, 'root' end assert_equal(writer.result.strip!, "\n") end def test_pi expected = "\n" writer = LibXML::XML::Writer.string document(writer) do assert(writer.start_pi('php')) assert(writer.write_string('echo "foo";')) assert(writer.end_pi) end assert_equal(writer.result.strip!, expected) writer = LibXML::XML::Writer.string document(writer) do assert(writer.write_pi('php', 'echo "foo";')) end assert_equal(writer.result.strip!, expected) end def test_comment expected = "\n" writer = LibXML::XML::Writer.string document(writer) do assert(writer.start_comment) assert(writer.write_string 'foo') assert(writer.end_comment) end assert_equal(writer.result.strip!, expected) writer = LibXML::XML::Writer.string document(writer) do assert(writer.write_comment 'foo') end assert_equal(writer.result.strip!, expected) end def test_cdata expected = "\n]]>" writer = LibXML::XML::Writer.string document(writer) do element writer, 'root' do assert(writer.start_cdata) assert(writer.write_string '') assert(writer.end_cdata) end end assert_equal(writer.result.strip!, expected) writer = LibXML::XML::Writer.string document(writer) do element writer, 'root' do assert(writer.write_cdata '') end end assert_equal(writer.result.strip!, expected) end def test_write_empty_elements writer = LibXML::XML::Writer.string document(writer) do assert(writer.write_element 'foo') end assert_equal(writer.result.strip!, "\n") writer = LibXML::XML::Writer.string document(writer) do assert(writer.write_element_ns XSL_PREFIX, 'stylesheet', XSL_URI) end assert_equal(writer.result.strip!, "\n<" + XSL_PREFIX + ":stylesheet xmlns:xsl=\"" + XSL_URI + "\"/>") end def test_valued_element expected = "\n123456789cueillir des cerisesnous irons au bois" writer = LibXML::XML::Writer.string document(writer) do assert(writer.start_element 'abc') assert(writer.write_string '123') assert(writer.start_element 'def') assert(writer.write_string '456') assert(writer.start_element 'ghi') assert(writer.write_string '789') assert(writer.end_element) assert(writer.write_string 'cueillir des cerises') assert(writer.end_element) assert(writer.write_string 'nous irons au bois') assert(writer.end_element) end assert_equal(writer.result.strip!, expected) writer = LibXML::XML::Writer.string document(writer) do assert(writer.start_element 'abc') assert(writer.write_string '123') assert(writer.start_element 'def') assert(writer.write_string '456') assert(writer.write_element 'ghi', '789') assert(writer.write_string 'cueillir des cerises') assert(writer.end_element) assert(writer.write_string 'nous irons au bois') assert(writer.end_element) end assert_equal(writer.result.strip!, expected) end def test_valued_element_ns expected = "\n" + "" + "" + "20px" + "solid" + "" + "" writer = LibXML::XML::Writer.string document(writer) do assert(writer.start_element_ns XSL_PREFIX, 'stylesheet', XSL_URI) assert(writer.start_element_ns XSL_PREFIX, 'attribute-set') assert(writer.start_element_ns XSL_PREFIX, 'attribute') assert(writer.write_string '20px') assert(writer.end_element) assert(writer.start_element_ns XSL_PREFIX, 'attribute') assert(writer.write_string 'solid') assert(writer.end_element) assert(writer.end_element) assert(writer.end_element) end assert_equal(writer.result.strip!, expected) writer = LibXML::XML::Writer.string document(writer) do assert(writer.start_element_ns XSL_PREFIX, 'stylesheet', XSL_URI) assert(writer.start_element_ns XSL_PREFIX, 'attribute-set') assert(writer.write_element_ns XSL_PREFIX, 'attribute', nil, '20px') assert(writer.write_element_ns XSL_PREFIX, 'attribute', nil, 'solid') assert(writer.end_element) assert(writer.end_element) end assert_equal(writer.result.strip!, expected) end def test_attribute writer = LibXML::XML::Writer.string document(writer) do element writer, 'root' do element writer, 'child' do assert(writer.start_attribute 'foo') assert(writer.write_string 'bar') assert(writer.end_attribute) end end end assert_equal(writer.result.strip!, "\n") writer = LibXML::XML::Writer.string document(writer) do element writer, 'root' do element writer, 'child' do assert(writer.write_attribute 'abc', 'def') assert(writer.write_string 'ghi') # must be done after attributes end end end assert_equal(writer.result.strip!, "\nghi") end def test_attribute_ns expected = "\n" writer = LibXML::XML::Writer.string document(writer) do element writer, 'root' do element writer, 'link' do assert(writer.write_attribute_ns 'xlink', 'href', nil, 'abc') assert(writer.write_attribute_ns 'xhtml', 'class', nil, 'def') end end end assert_equal(writer.result.strip!, expected) writer = LibXML::XML::Writer.string document(writer) do element writer, 'root' do element writer, 'link' do assert(writer.start_attribute_ns 'xlink', 'href') assert(writer.write_string 'abc') assert(writer.end_attribute) assert(writer.start_attribute_ns 'xhtml', 'class') assert(writer.write_string 'def') assert(writer.end_attribute) end end end assert_equal(writer.result.strip!, expected) end def test_quote_char if LibXML::XML::Writer.method_defined? :set_quote_char writer = LibXML::XML::Writer.string writer.set_quote_char "'" document(writer) do element writer, 'root' do assert(writer.start_attribute 'abc') assert(writer.write_string 'def') assert(writer.end_attribute) end end assert(writer.result.strip!.end_with? "") end end def test_indentation_on if LibXML::XML::Writer.method_defined? :set_indent writer = LibXML::XML::Writer.string assert(writer.set_indent true) document(writer) do element writer, 'root' do element writer, 'child' do assert(writer.start_attribute 'abc') assert(writer.write_string 'def') assert(writer.end_attribute) end end end assert_equal(writer.result.strip!, "\n\n \n") end end def test_indentation_string if LibXML::XML::Writer.method_defined? :set_indent_string writer = LibXML::XML::Writer.string assert(writer.set_indent true) assert(writer.set_indent_string ' ' * 4) document(writer) do element writer, 'root' do element writer, 'child' do assert(writer.start_attribute 'abc') assert(writer.write_string 'def') assert(writer.end_attribute) end end end assert_equal(writer.result.strip!, "\n\n \n") end end def test_dtd_declaration writer = LibXML::XML::Writer.string dtd writer, 'html' assert_equal(writer.result, '') writer = LibXML::XML::Writer.string dtd writer, 'html', '-//W3C//DTD XHTML 1.0 Strict//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd' assert_equal(writer.result, '') end def test_dtd_attlist expected = ']>' writer = LibXML::XML::Writer.string dtd writer, 'http' do assert(writer.start_dtd_attlist 'method') assert(writer.write_string '(get|post) "get"') assert(writer.end_dtd_attlist) end assert_equal(writer.result, expected) writer = LibXML::XML::Writer.string dtd writer, 'http' do assert(writer.write_dtd_attlist 'method', '(get|post) "get"') end assert_equal(writer.result, expected) end def test_dtd_element expected = ']>' writer = LibXML::XML::Writer.string dtd writer, 'html' do assert(writer.start_dtd_element 'dl') assert(writer.write_string '(dt|dd)+') assert(writer.end_dtd_element) end assert_equal(writer.result, expected) writer = LibXML::XML::Writer.string dtd writer, 'html' do assert(writer.write_dtd_element 'dl', '(dt|dd)+') end assert_equal(writer.result, expected) end def test_dtd_entity # parameterized entity expected = ']>' writer = LibXML::XML::Writer.string dtd writer, 'html' do assert(writer.start_dtd_entity 'special.pre', true) assert(writer.write_string 'br | span | bdo | map') assert(writer.end_dtd_entity) assert(writer.start_dtd_entity 'special', true) assert(writer.write_string '%special.pre; | object | img') assert(writer.end_dtd_entity) end assert_equal(writer.result, expected) writer = LibXML::XML::Writer.string dtd writer, 'html' do assert(writer.write_dtd_internal_entity 'special.pre', 'br | span | bdo | map', true) assert(writer.write_dtd_internal_entity 'special', '%special.pre; | object | img', true) end assert_equal(writer.result, expected) # non parameterized entity expected = ']>' writer = LibXML::XML::Writer.string dtd writer, 'html' do assert(writer.start_dtd_entity 'Alpha') assert(writer.write_string 'Α') assert(writer.end_dtd_entity) end assert_equal(writer.result, expected) writer = LibXML::XML::Writer.string dtd writer, 'html' do assert(writer.start_dtd_entity 'Alpha', false) assert(writer.write_string 'Α') assert(writer.end_dtd_entity) end assert_equal(writer.result, expected) writer = LibXML::XML::Writer.string dtd writer, 'html' do assert(writer.write_dtd_internal_entity 'Alpha', 'Α', false) end assert_equal(writer.result, expected) end def test_dtd_notation writer = LibXML::XML::Writer.string dtd writer, 'pictures' do assert(writer.write_dtd_notation 'GIF89a', '-//Compuserve//NOTATION Graphics Interchange Format 89a//EN', nil) assert(writer.write_dtd_external_entity 'pictures', nil, 'images/plage.gif', 'GIF89a', false) end assert_equal(writer.result, ']>') end def test_encoding iso = 'éloïse'.encode 'ISO-8859-1' writer = LibXML::XML::Writer.string document(writer) do assert(writer.write_element iso) end assert_equal(writer.result.strip!, "\n<éloïse/>") end def test_flush writer = LibXML::XML::Writer.string assert(writer.start_document) assert_equal(writer.flush.strip!, '') assert(writer.start_element 'foo') assert(writer.end_element) assert(writer.end_document) writer.flush false assert_equal(writer.result.strip, '') end def test_nil_pe_issue expected = ']>' writer = LibXML::XML::Writer.string dtd writer, 'html' do assert(writer.write_dtd_internal_entity 'special.pre', 'br | span | bdo | map', nil) assert(writer.write_dtd_internal_entity 'special', '%special.pre; | object | img', nil) end assert_equal(writer.result, expected) end private def document(writer, options = {}) assert(writer.start_document options) yield if block_given? assert(writer.end_document) end def dtd(writer, name, pubid = nil, sysid = nil) assert(writer.start_dtd name, pubid, sysid) yield if block_given? assert(writer.end_dtd) end def element(writer, localname) assert(writer.start_element localname) yield if block_given? assert(writer.end_element) end end libxml-ruby-5.0.3/test/test_parser_context.rb0000644000004100000410000001270514620142101021414 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestParserContext < Minitest::Test def test_string # UTF8 xml = <<-EOS m\303\266tley_cr\303\274e EOS context = LibXML::XML::Parser::Context.string(xml) assert_instance_of(LibXML::XML::Parser::Context, context) assert_equal(LibXML::XML::Encoding::NONE, context.encoding) assert_nil(context.base_uri) end def test_encoding # ISO_8859_1: xml = <<-EOS m\366tley_cr\374e EOS context = LibXML::XML::Parser::Context.string(xml) assert_equal(LibXML::XML::Encoding::NONE, context.encoding) context.encoding = LibXML::XML::Encoding::ISO_8859_1 assert_equal(LibXML::XML::Encoding::ISO_8859_1, context.encoding) end def test_invalid_encoding # UTF8 xml = <<-EOS m\303\266tley_cr\303\274e EOS context = LibXML::XML::Parser::Context.string(xml) error = assert_raises(ArgumentError) do context.encoding = -999 end assert_equal("Unknown encoding: -999", error.to_s) end def test_base_uri # UTF8 xml = <<-EOS m\303\266tley_cr\303\274e EOS context = LibXML::XML::Parser::Context.string(xml) assert_nil(context.base_uri) context.base_uri = 'http://libxml.rubyforge.org' assert_equal('http://libxml.rubyforge.org', context.base_uri) end def test_string_empty error = assert_raises(TypeError) do LibXML::XML::Parser::Context.string(nil) end assert_equal("wrong argument type nil (expected String)", error.to_s) error = assert_raises(ArgumentError) do LibXML::XML::Parser::Context.string('') end assert_equal("Must specify a string with one or more characters", error.to_s) end def test_well_formed parser = LibXML::XML::Parser.string("") parser.parse assert(parser.context.well_formed?) end def test_not_well_formed parser = LibXML::XML::Parser.string("") assert_raises(LibXML::XML::Error) do parser.parse end assert(!parser.context.well_formed?) end def test_version_info file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.utf-8.xml')) parser = LibXML::XML::Parser.file(file) assert_nil(parser.context.version) parser.parse assert_equal("1.0", parser.context.version) end def test_depth context = LibXML::XML::Parser::Context.new assert_instance_of(Integer, context.depth) end def test_disable_sax context = LibXML::XML::Parser::Context.new assert(!context.disable_sax?) end def test_docbook context = LibXML::XML::Parser::Context.new assert(!context.docbook?) end def test_html context = LibXML::XML::Parser::Context.new assert(!context.html?) end def test_keep_blanks context = LibXML::XML::Parser::Context.new if context.keep_blanks? assert_instance_of(TrueClass, context.keep_blanks?) else assert_instance_of(FalseClass, context.keep_blanks?) end end def test_replace_entities context = LibXML::XML::Parser::Context.new assert(!context.replace_entities?) context.options = LibXML::XML::Parser::Options::NOENT assert(context.replace_entities?) context.options = 0 assert(!context.replace_entities?) context.replace_entities = true assert(context.replace_entities?) end def test_space_depth context = LibXML::XML::Parser::Context.new assert_equal(1, context.space_depth) end def test_subset_external context = LibXML::XML::Parser::Context.new assert(!context.subset_external?) end def test_data_directory_get context = LibXML::XML::Parser::Context.new assert_nil(context.data_directory) end def test_parse_error xp = LibXML::XML::Parser.string('') assert_raises(LibXML::XML::Error) do xp.parse end # Now check context context = xp.context assert_nil(context.data_directory) assert_equal(0, context.depth) assert_equal(true, context.disable_sax?) assert_equal(false, context.docbook?) assert_equal(LibXML::XML::Encoding::NONE, context.encoding) assert_equal(76, context.errno) assert_equal(false, context.html?) assert_equal(5, context.io_max_num_streams) assert_equal(1, context.io_num_streams) assert_equal(true, context.keep_blanks?) assert_equal(1, context.io_num_streams) assert_nil(context.name_node) assert_equal(0, context.name_depth) assert_equal(10, context.name_depth_max) assert([0, 17].include?(context.num_chars)) assert_equal(false, context.replace_entities?) assert_equal(1, context.space_depth) assert_equal(10, context.space_depth_max) assert_equal(false, context.subset_external?) assert_nil(context.subset_external_system_id) assert_nil(context.subset_external_uri) assert_equal(false, context.subset_internal?) assert_nil(context.subset_internal_name) assert_equal(false, context.stats?) assert_equal(true, context.standalone?) assert_equal(false, context.valid) assert_equal(false, context.validate?) assert_equal('1.0', context.version) assert_equal(false, context.well_formed?) end end libxml-ruby-5.0.3/test/test_node_write.rb0000644000004100000410000001056414620142101020514 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestNodeWrite < Minitest::Test def setup load_encoding("utf-8") end def teardown @doc = nil end def load_encoding(name) @encoding = Encoding.find(name) @file_name = "model/bands.#{name.downcase}.xml" file = File.join(File.dirname(__FILE__), @file_name) @doc = LibXML::XML::Document.file(file, options: LibXML::XML::Parser::Options::NOBLANKS) end def test_to_s_default # Default to_s has indentation node = @doc.root assert_equal(Encoding::UTF_8, node.to_s.encoding) assert_equal("\n M\303\266tley Cr\303\274e is an American heavy metal band formed in Los Angeles, California in 1981.\n Iron Maiden is a British heavy metal band formed in 1975.\n", node.to_s) end def test_to_s_no_global_indentation # No indentation due to global setting node = @doc.root LibXML::XML.indent_tree_output = false assert_equal("\nM\303\266tley Cr\303\274e is an American heavy metal band formed in Los Angeles, California in 1981.\nIron Maiden is a British heavy metal band formed in 1975.\n", node.to_s) ensure LibXML::XML.indent_tree_output = true end def test_to_s_no_indentation # No indentation due to local setting node = @doc.root assert_equal("M\303\266tley Cr\303\274e is an American heavy metal band formed in Los Angeles, California in 1981.Iron Maiden is a British heavy metal band formed in 1975.", node.to_s(:indent => false)) end def test_to_s_level # No indentation due to local setting node = @doc.root assert_equal("\n M\303\266tley Cr\303\274e is an American heavy metal band formed in Los Angeles, California in 1981.\n Iron Maiden is a British heavy metal band formed in 1975.\n ", node.to_s(:level => 1)) end def test_to_s_encoding # Test encodings node = @doc.root # UTF8: # ö - c3 b6 in hex, \303\266 in octal # ü - c3 bc in hex, \303\274 in octal value = node.to_s(:encoding => LibXML::XML::Encoding::UTF_8) assert_equal(Encoding::UTF_8, node.to_s.encoding) assert_equal("\n M\303\266tley Cr\303\274e is an American heavy metal band formed in Los Angeles, California in 1981.\n Iron Maiden is a British heavy metal band formed in 1975.\n", value) # ISO_8859_1: # ö - f6 in hex, \366 in octal # ü - fc in hex, \374 in octal value = node.to_s(:encoding => LibXML::XML::Encoding::ISO_8859_1) assert_equal(Encoding::ISO8859_1, value.encoding) assert_equal("\n M\xF6tley Cr\xFCe is an American heavy metal band formed in Los Angeles, California in 1981.\n Iron Maiden is a British heavy metal band formed in 1975.\n".force_encoding(Encoding::ISO8859_1), value) # Invalid encoding error = assert_raises(ArgumentError) do node.to_s(:encoding => -9999) end assert_equal('Unknown encoding value: -9999', error.to_s) end def test_inner_xml # Default to_s has indentation node = @doc.root assert_equal(Encoding::UTF_8, node.inner_xml.encoding) assert_equal("M\u00F6tley Cr\u00FCe is an American heavy metal band formed in Los Angeles, California in 1981.Iron Maiden is a British heavy metal band formed in 1975.", node.inner_xml) end # --- Debug --- def test_debug assert(@doc.root.debug) end endlibxml-ruby-5.0.3/test/c14n/0000755000004100000410000000000014620142101015530 5ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/given/0000755000004100000410000000000014620142101016640 5ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/given/doc.dtd0000644000004100000410000000002214620142101020074 0ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/given/world.txt0000644000004100000410000000000514620142101020523 0ustar www-datawww-dataworldlibxml-ruby-5.0.3/test/c14n/given/example-1.xml0000644000004100000410000000035614620142101021157 0ustar www-datawww-data Hello, world! libxml-ruby-5.0.3/test/c14n/given/example-8.xpath0000644000004100000410000000040514620142101021505 0ustar www-datawww-data (//.|//@*|//namespace::*) [ self::ietf:e1 or (parent::ietf:e1 and not(self::text() or self::e2)) or count(id("E3")|ancestor-or-self::node()) = count(ancestor-or-self::node()) ] libxml-ruby-5.0.3/test/c14n/given/example-2.xml0000644000004100000410000000026514620142101021157 0ustar www-datawww-data A B A B A B C libxml-ruby-5.0.3/test/c14n/given/example-4.xml0000644000004100000410000000065214620142101021161 0ustar www-datawww-data]> First line Second line 2 "0" && value<"10" ?"valid":"error"]]> valid libxml-ruby-5.0.3/test/c14n/given/example-6.xml0000644000004100000410000000010014620142101021147 0ustar www-datawww-data © libxml-ruby-5.0.3/test/c14n/given/example-3.xml0000644000004100000410000000115514620142101021157 0ustar www-datawww-data]> libxml-ruby-5.0.3/test/c14n/given/example-5.xml0000644000004100000410000000051014620142101021153 0ustar www-datawww-data ]> &ent1;, &ent2;! libxml-ruby-5.0.3/test/c14n/given/example-7.xml0000644000004100000410000000040014620142101021153 0ustar www-datawww-data ]> libxml-ruby-5.0.3/test/c14n/given/example-8.xml0000644000004100000410000000050614620142101021163 0ustar www-datawww-data ]> libxml-ruby-5.0.3/test/c14n/result/0000755000004100000410000000000014620142101017046 5ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/0000755000004100000410000000000014620142101022670 5ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/example-20000644000004100000410000000026314620142101024406 0ustar www-datawww-data A B A B A B C libxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/example-80000644000004100000410000000023714620142101024415 0ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/example-40000644000004100000410000000060114620142101024404 0ustar www-datawww-data First line Second line 2 value>"0" && value<"10" ?"valid":"error" valid libxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/example-10000644000004100000410000000014714620142101024406 0ustar www-datawww-data Hello, world! libxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/example-30000644000004100000410000000074514620142101024414 0ustar www-datawww-data libxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/example-60000644000004100000410000000001514620142101024405 0ustar www-datawww-data©libxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/example-70000644000004100000410000000016214620142101024411 0ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/result/1-1-without-comments/example-50000644000004100000410000000006314620142101024407 0ustar www-datawww-data Hello, world! libxml-ruby-5.0.3/test/c14n/result/with-comments/0000755000004100000410000000000014620142101021644 5ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/result/with-comments/example-20000644000004100000410000000026314620142101023362 0ustar www-datawww-data A B A B A B C libxml-ruby-5.0.3/test/c14n/result/with-comments/example-40000644000004100000410000000060114620142101023360 0ustar www-datawww-data First line Second line 2 value>"0" && value<"10" ?"valid":"error" valid libxml-ruby-5.0.3/test/c14n/result/with-comments/example-10000644000004100000410000000024114620142101023355 0ustar www-datawww-data Hello, world! libxml-ruby-5.0.3/test/c14n/result/with-comments/example-30000644000004100000410000000074514620142101023370 0ustar www-datawww-data libxml-ruby-5.0.3/test/c14n/result/with-comments/example-60000644000004100000410000000001514620142101023361 0ustar www-datawww-data©libxml-ruby-5.0.3/test/c14n/result/with-comments/example-70000644000004100000410000000016214620142101023365 0ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/result/with-comments/example-50000644000004100000410000000016214620142101023363 0ustar www-datawww-data Hello, world! libxml-ruby-5.0.3/test/c14n/result/without-comments/0000755000004100000410000000000014620142101022374 5ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/result/without-comments/example-20000644000004100000410000000026314620142101024112 0ustar www-datawww-data A B A B A B C libxml-ruby-5.0.3/test/c14n/result/without-comments/example-40000644000004100000410000000060114620142101024110 0ustar www-datawww-data First line Second line 2 value>"0" && value<"10" ?"valid":"error" valid libxml-ruby-5.0.3/test/c14n/result/without-comments/example-10000644000004100000410000000014714620142101024112 0ustar www-datawww-data Hello, world! libxml-ruby-5.0.3/test/c14n/result/without-comments/example-30000644000004100000410000000074514620142101024120 0ustar www-datawww-data libxml-ruby-5.0.3/test/c14n/result/without-comments/example-60000644000004100000410000000001514620142101024111 0ustar www-datawww-data©libxml-ruby-5.0.3/test/c14n/result/without-comments/example-70000644000004100000410000000016214620142101024115 0ustar www-datawww-datalibxml-ruby-5.0.3/test/c14n/result/without-comments/example-50000644000004100000410000000006314620142101024113 0ustar www-datawww-data Hello, world! libxml-ruby-5.0.3/test/test_schema.rb0000644000004100000410000002055714620142101017620 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestSchema < Minitest::Test Import_NS = 'http://xml4r.org/libxml-ruby/test/shiporder'.freeze def setup file = File.join(File.dirname(__FILE__), 'model/shiporder.xml') @doc = LibXML::XML::Document.file(file) schema_file = File.join(File.dirname(__FILE__), 'model/shiporder.xsd') schema_doc = LibXML::XML::Document.file(schema_file) @schema = LibXML::XML::Schema.document(schema_doc) end def teardown @doc = nil @schema = nil end def check_error(error) refute_nil(error) assert(error.message.match(/Error: Element 'invalid': This element is not expected. Expected is \( item \)/)) assert_kind_of(LibXML::XML::Error, error) assert_equal(LibXML::XML::Error::SCHEMASV, error.domain) assert_equal(LibXML::XML::Error::SCHEMAV_ELEMENT_CONTENT, error.code) assert_equal(LibXML::XML::Error::ERROR, error.level) assert(error.file.match(/shiporder.xml/)) if error.file assert_nil(error.str1) assert_nil(error.str2) assert_nil(error.str3) assert_equal(0, error.int1) assert_equal(0, error.int2) end def test_load_from_doc assert_instance_of(LibXML::XML::Schema, @schema) end def test_schema_load_from_uri xlink_schema = LibXML::XML::Schema.new('http://www.w3.org/1999/xlink.xsd') assert_instance_of(LibXML::XML::Schema, xlink_schema) assert_instance_of(LibXML::XML::Schema::Element, xlink_schema.elements['title']) assert_instance_of(LibXML::XML::Schema::Type, xlink_schema.types['titleEltType']) assert_equal('http://www.w3.org/1999/xlink', xlink_schema.target_namespace) end def test_schema_from_string schema_file = File.join(File.dirname(__FILE__), 'model/shiporder.xsd') schema_from_str = LibXML::XML::Schema.from_string(File.read(schema_file)) assert_instance_of(LibXML::XML::Schema, schema_from_str) end def test_invalid_schema_doc bad_schema_file = File.join(File.dirname(__FILE__), 'model/shiporder_bad.xsd') bad_schema_doc = LibXML::XML::Document.file(bad_schema_file) bad_schema = nil ## Note: this type of error throws begin bad_schema = LibXML::XML::Schema.document(bad_schema_doc) rescue LibXML::XML::Error => error bad_schema = error assert(error.message.match(/Error: Element '.*': The content is not valid. Expected is \(/)) assert_kind_of(LibXML::XML::Error, error) assert_equal(LibXML::XML::Error::SCHEMASP, error.domain) assert_equal(LibXML::XML::Error::SCHEMAP_S4S_ELEM_NOT_ALLOWED, error.code) assert_equal(LibXML::XML::Error::ERROR, error.level) assert(error.file.match(/shiporder_bad.xsd/)) assert_equal("Element '{http://www.w3.org/2001/XMLSchema}complexType'", error.str1) refute_nil(error.str2) assert_nil(error.str3) assert_equal(0, error.int1) assert_equal(0, error.int2) end ## Last but not least, make sure we threw an error assert_instance_of(LibXML::XML::Error, bad_schema) end def test_doc_valid assert(@doc.validate_schema(@schema)) end def test_doc_invalid new_node = LibXML::XML::Node.new('invalid', 'this will mess up validation') @doc.root << new_node error = assert_raises(LibXML::XML::Error) do @doc.validate_schema(@schema) end check_error(error) assert_nil(error.line) refute_nil(error.node) assert_equal('invalid', error.node.name) end def test_reader_valid reader = LibXML::XML::Reader.string(@doc.to_s) assert(reader.schema_validate(@schema)) while reader.read end end def test_reader_invalid # Set error handler errors = Array.new LibXML::XML::Error.set_handler do |error| errors << error end new_node = LibXML::XML::Node.new('invalid', 'this will mess up validation') @doc.root << new_node reader = LibXML::XML::Reader.string(@doc.to_s) # Set a schema assert(reader.schema_validate(@schema)) while reader.read end assert_equal(1, errors.length) error = errors.first check_error(error) assert_equal(21, error.line) ensure LibXML::XML::Error.set_handler(&LibXML::XML::Error::VERBOSE_HANDLER) end # Schema meta-data tests def test_elements assert_instance_of(Hash, @schema.elements) assert_equal(1, @schema.elements.length) assert_instance_of(LibXML::XML::Schema::Element, @schema.elements['shiporder']) end def test_types assert_instance_of(Hash, @schema.types) assert_equal(1, @schema.types.length) assert_instance_of(LibXML::XML::Schema::Type, @schema.types['shiporderType']) end def test_imported_types assert_instance_of(Hash, @schema.imported_types) assert_equal(2, @schema.imported_types.length) assert_instance_of(LibXML::XML::Schema::Type, @schema.imported_types['shiporderType']) assert_instance_of(LibXML::XML::Schema::Type, @schema.imported_types['shiporderFooType']) end def test_imported_ns_types assert_instance_of(Hash, @schema.imported_ns_types) assert_equal(2, @schema.imported_ns_types.length) assert_equal(1, @schema.imported_ns_types[nil].length) assert_equal(1, @schema.imported_ns_types[Import_NS].length) assert_instance_of(LibXML::XML::Schema::Type, @schema.imported_ns_types[nil]['shiporderType']) assert_instance_of(LibXML::XML::Schema::Type, @schema.imported_ns_types[Import_NS]['shiporderFooType']) end def test_imported_ns_elements assert_instance_of(Hash, @schema.imported_ns_elements) assert_equal(2, @schema.imported_ns_elements.length) assert_equal(1, @schema.imported_ns_elements[nil].length) assert_equal(1, @schema.imported_ns_elements[Import_NS].length) assert_instance_of(LibXML::XML::Schema::Element, @schema.imported_ns_elements[nil]['shiporder']) assert_instance_of(LibXML::XML::Schema::Element, @schema.imported_ns_elements[Import_NS]['shiporder']) assert_equal('shiporderType', @schema.imported_ns_elements[nil]['shiporder'].type.name) assert_equal('shiporderFooType', @schema.imported_ns_elements[Import_NS]['shiporder'].type.name) end def test_namespaces assert_instance_of(Array, @schema.namespaces) ## For some reason, when importing another schema we end up with two xs->http://www.w3.org/2001/XMLSchema namespaces. ## So, we expect 3 here (one for Import_NS and then two for the schema namespace. assert_equal(3, @schema.namespaces.length) end def test_schema_type type = @schema.types['shiporderType'] assert_equal('shiporderType', type.name) assert_nil(type.namespace) assert_equal("Shiporder type documentation", type.annotation) assert_instance_of(LibXML::XML::Node, type.node) assert_equal(LibXML::XML::Schema::Types::XML_SCHEMA_TYPE_COMPLEX, type.kind) assert_instance_of(LibXML::XML::Schema::Type, type.base) assert_equal("anyType", type.base.name) assert_equal(LibXML::XML::Schema::Types::XML_SCHEMA_TYPE_BASIC, type.base.kind) assert_instance_of(Hash, type.elements) assert_equal(3, type.elements.length) end def test_schema_element element = @schema.types['shiporderType'].elements['orderperson'] assert_equal('orderperson', element.name) assert_nil(element.namespace) assert_equal("orderperson element documentation", element.annotation) assert_equal(false, element.array?) assert_equal(true, element.required?) element = @schema.types['shiporderType'].elements['item'] assert_equal('item', element.name) assert_equal(true, element.array?) assert_equal(true, element.required?) element = @schema.types['shiporderType'].elements['item'].type.elements['note'] assert_equal('note', element.name) assert_equal('string', element.type.name) assert_equal(false, element.array?) assert_equal(false, element.required?) end def test_schema_attributes type = @schema.types['shiporderType'] assert_instance_of(Array, type.attributes) assert_equal(2, type.attributes.length) assert_instance_of(LibXML::XML::Schema::Attribute, type.attributes.first) end def test_schema_attribute attribute = @schema.types['shiporderType'].attributes.first assert_equal("orderid", attribute.name) assert_nil(attribute.namespace) assert_equal(1, attribute.occurs) assert_equal('string', attribute.type.name) attribute = @schema.types['shiporderType'].attributes[1] assert_equal(2, attribute.occurs) assert_equal('1', attribute.default) assert_equal('integer', attribute.type.name) end end libxml-ruby-5.0.3/test/test_node_copy.rb0000644000004100000410000000160614620142101020331 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' # see mailing list archive # [libxml-devel] Segmentation fault when add the cloned/copied node # 2007/11/27 20:51 class TestNodeCopy < Minitest::Test def setup str = <<-STR
foo
bar
STR doc = LibXML::XML::Parser.string(str).parse xpath = "//div" @div1 = doc.find(xpath).to_a[0] @div2 = doc.find(xpath).to_a[1] end def test_libxml_node_copy_not_segv @div2.each do |child| c = child.copy(false) @div1 << c end assert @div1.to_s =~ /foo/ end def test_libxml_node_clone_not_segv @div2.each do |child| c = child.clone @div1 << c end assert @div1.to_s =~ /foo/ end end libxml-ruby-5.0.3/test/test_encoding_sax.rb0000644000004100000410000000610414620142101021011 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class SaxEncodingCallbacks attr_reader :encoding attr_accessor :assertions include Minitest::Assertions def initialize @assertions = 0 @encoding = Encoding::UTF_8 end # Called for a CDATA block event. def on_cdata_block(cdata) assert_equal(self.encoding, cdata.encoding) end # Called for a characters event. def on_characters(chars) assert_equal(self.encoding, chars.encoding) end # Called for a comment event. def on_comment(msg) assert_equal(self.encoding, msg.encoding) end # Called for a end document event. def on_end_document end # Called for a end element event. def on_end_element_ns(name, prefix, uri) assert_equal(self.encoding, name.encoding) assert_equal(self.encoding, prefix.encoding) if prefix assert_equal(self.encoding, uri.encoding) if uri end # Called for parser errors. def on_error(msg) assert_equal(self.encoding, msg.encoding) end # Called for an external subset event. def on_external_subset(name, external_id, system_id) assert_equal(self.encoding, name.encoding) assert_equal(self.encoding, external_id.encoding) assert_equal(self.encoding, system_id.encoding) end # Called for an external subset notification event. def on_has_external_subset end # Called for an internal subset notification event. def on_has_internal_subset end # Called for an internal subset event. def on_internal_subset(name, external_id, system_id) assert_equal(self.encoding, name.encoding) assert_equal(self.encoding, external_id.encoding) assert_equal(self.encoding, system_id.encoding) end # Called for 'is standalone' event. def on_is_standalone end # Called for an processing instruction event. def on_processing_instruction(target, data) assert_equal(self.encoding, target.encoding) assert_equal(self.encoding, data.encoding) end # Called for a reference event. def on_reference(name) assert_equal(self.encoding, name.encoding) end # Called for a start document event. def on_start_document end # Called for a start element event. def on_start_element_ns(name, attributes, prefix, uri, namespaces) assert_equal(self.encoding, name.encoding) if name assert_equal(self.encoding, prefix.encoding) if prefix assert_equal(self.encoding, uri.encoding) if uri end end class TestEncodingSax < Minitest::Test def setup Encoding.default_internal = nil end def file_for_encoding(encoding) file_name = "model/bands.#{encoding.name.downcase}.xml" File.join(File.dirname(__FILE__), file_name) end def test_encoding_iso_8859_1 parser = LibXML::XML::SaxParser.file(file_for_encoding(Encoding::ISO_8859_1)) parser.callbacks = SaxEncodingCallbacks.new parser.parse end def test_encoding_utf8 parser = LibXML::XML::SaxParser.file(file_for_encoding(Encoding::UTF_8)) parser.callbacks = SaxEncodingCallbacks.new parser.parse end endlibxml-ruby-5.0.3/test/test_attributes.rb0000644000004100000410000000773614620142101020552 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class AttributesTest < Minitest::Test def setup xp = LibXML::XML::Parser.string(<<-EOS) EOS @doc = xp.parse end def teardown @doc = nil end def city_member @doc.find('/city:CityModel/city:cityMember').first end def test_attributes attributes = city_member.attributes assert_instance_of(LibXML::XML::Attributes, attributes) assert_equal(5, attributes.length) end def test_each attributes = city_member.attributes length = attributes.inject(0) do |result, attr| assert_instance_of(LibXML::XML::Attr, attr) result + 1 end assert_equal(5, length) end def test_get_attribute attributes = city_member.attributes attr = attributes.get_attribute('name') assert_instance_of(LibXML::XML::Attr, attr) attr = attributes.get_attribute('does_not_exist') assert_nil(attr) attr = attributes.get_attribute('name') assert_instance_of(LibXML::XML::Attr, attr) attr = attributes.get_attribute('href') assert_instance_of(LibXML::XML::Attr, attr) assert_instance_of(LibXML::XML::Namespace, attr.ns) assert_equal('xlink', attr.ns.prefix) assert_equal('http://www.w3.org/1999/xlink', attr.ns.href) attr = attributes.get_attribute_ns('http://www.w3.org/1999/xlink', 'href') assert_instance_of(LibXML::XML::Attr, attr) attr = attributes.get_attribute_ns('http://www.opengis.net/gml', 'remoteSchema') assert_instance_of(LibXML::XML::Attr, attr) attr = attributes.get_attribute_ns('http://i.dont.exist', 'nor do i') assert_nil(attr) end def test_get_values assert_equal('Cambridge', city_member[:name]) assert_equal('http://www.foo.net/cgi-bin/wfs?FeatureID=C10239', city_member[:href]) attributes = city_member.attributes assert_equal('Cambridge', attributes[:name]) assert_equal('http://www.foo.net/cgi-bin/wfs?FeatureID=C10239', attributes[:href]) end def test_get_values_gc # There used to be a bug caused by accessing an # attribute over and over and over again. 20000.times do @doc.root.attributes["key"] end end def test_set_values city_member[:name] = 'London' assert_equal('London', city_member[:name]) city_member[:href] = 'foo' assert_equal('foo', city_member[:href]) attributes = city_member.attributes attributes[:name] = 'London' assert_equal('London', attributes[:name]) attributes[:href] = 'foo' assert_equal('foo', attributes[:href]) end def test_str_sym() attributes = city_member.attributes assert_equal('Cambridge', attributes[:name]) assert_equal('Cambridge', attributes['name']) end def test_remove_first attributes = @doc.find_first('/city:CityModel/city:cityMember').attributes assert_equal(5, attributes.length) attr = attributes.first attr.remove! assert_equal(4, attributes.length) end def test_remove_all node = @doc.find_first('/city:CityModel/city:cityMember') assert_equal(5, node.attributes.length) attrs = Array.new node.attributes.each do |attr| attrs << attr attr.remove! end assert_equal(5, attrs.length) assert_equal(0, node.attributes.length) end endlibxml-ruby-5.0.3/test/test.rb0000644000004100000410000000010314620142101016261 0ustar www-datawww-databegin File.open("/does/not/exist") rescue => e puts e end libxml-ruby-5.0.3/test/test_namespaces.rb0000644000004100000410000001666314620142101020502 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestNamespaces < Minitest::Test def setup file = File.join(File.dirname(__FILE__), 'model/soap.xml') @doc = LibXML::XML::Document.file(file) end def teardown @doc = nil end def test_namespace_node node = @doc.root ns = node.namespaces.namespace assert_equal('soap', ns.prefix) assert_equal('http://schemas.xmlsoap.org/soap/envelope/', ns.href) end def test_namespace_attr node = @doc.root attr = node.attributes.get_attribute('encodingStyle') assert_equal('soap', attr.ns.prefix) assert_equal('soap', attr.namespaces.namespace.prefix) end def test_set_namespace_node node = LibXML::XML::Node.new('Envelope') assert_equal('', node.to_s) ns = LibXML::XML::Namespace.new(node, 'soap', 'http://schemas.xmlsoap.org/soap/envelope/') assert_equal("", node.to_s) assert_nil(node.namespaces.namespace) # Now put the node in the soap namespace node.namespaces.namespace = ns refute_nil(node.namespaces.namespace) assert_equal("", node.to_s) end def test_set_namespace_attribute # Create node node = LibXML::XML::Node.new('Envelope') assert_equal('', node.to_s) # Create attribute attr = LibXML::XML::Attr.new(node, "encodingStyle", "http://www.w3.org/2001/12/soap-encoding") assert_equal('', node.to_s) # Create namespace attribute ns = LibXML::XML::Namespace.new(node, 'soap', 'http://schemas.xmlsoap.org/soap/envelope/') assert_equal('', node.to_s) assert_nil(node.namespaces.namespace) # Now put the node in the soap namespace node.namespaces.namespace = ns refute_nil(node.namespaces.namespace) assert_equal('', node.to_s) # Now put the attribute in the soap namespace attr.namespaces.namespace = ns refute_nil(node.namespaces.namespace) assert_equal('', node.to_s) end def test_define_namespace node = LibXML::XML::Node.new('Envelope') assert_equal('', node.to_s) LibXML::XML::Namespace.new(node, 'soap', 'http://schemas.xmlsoap.org/soap/envelope/') assert_equal("", node.to_s) assert_nil(node.namespaces.namespace) end def test_define_default_namespace node = LibXML::XML::Node.new('Envelope') assert_equal('', node.to_s) LibXML::XML::Namespace.new(node, nil, 'http://schemas.xmlsoap.org/soap/envelope/') assert_equal("", node.to_s) # This seems wrong, but appears to be the way libxml works assert_nil(node.namespaces.namespace) end def test_namespaces node = @doc.find_first('//ns1:IdAndName', :ns1 => 'http://domain.somewhere.com') namespaces = node.namespaces.sort assert_equal(5, namespaces.length) namespace = namespaces[0] assert_instance_of(LibXML::XML::Namespace, namespace) assert_nil(namespace.prefix) assert_equal('http://services.somewhere.com', namespace.href) namespace = namespaces[1] assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('ns1', namespace.prefix) assert_equal('http://domain.somewhere.com', namespace.href) namespace = namespaces[2] assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('soap', namespace.prefix) assert_equal('http://schemas.xmlsoap.org/soap/envelope/', namespace.href) namespace = namespaces[3] assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('xsd', namespace.prefix) assert_equal('http://www.w3.org/2001/XMLSchema', namespace.href) namespace = namespaces[4] assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('xsi', namespace.prefix) assert_equal('http://www.w3.org/2001/XMLSchema-instance', namespace.href) end def test_namespace_definitions ns_defs = @doc.root.namespaces.definitions assert_equal(3, ns_defs.size) namespace = ns_defs[0] assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('soap', namespace.prefix) assert_equal('http://schemas.xmlsoap.org/soap/envelope/', namespace.href) namespace = ns_defs[1] assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('xsd', namespace.prefix) assert_equal('http://www.w3.org/2001/XMLSchema', namespace.href) namespace = ns_defs[2] assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('xsi', namespace.prefix) assert_equal('http://www.w3.org/2001/XMLSchema-instance', namespace.href) node = @doc.root.find_first('//ns:getManufacturerNamesResponse', :ns => 'http://services.somewhere.com') ns_defs = node.namespaces.definitions assert_equal(1, ns_defs.size) namespace = ns_defs[0] assert_instance_of(LibXML::XML::Namespace, namespace) assert_nil(namespace.prefix) assert_equal('http://services.somewhere.com', namespace.href) end def test_find_by_prefix namespace = @doc.root.namespaces.find_by_prefix('soap') assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('soap', namespace.prefix) assert_equal('http://schemas.xmlsoap.org/soap/envelope/', namespace.href) end def test_find_default_ns namespace = @doc.root.namespaces.find_by_prefix(nil) assert_nil(namespace) node = @doc.find_first('//ns1:getManufacturerNamesResponse', :ns1 => 'http://services.somewhere.com') namespace = node.namespaces.find_by_prefix(nil) assert_instance_of(LibXML::XML::Namespace, namespace) assert_nil(namespace.prefix) assert_equal('http://services.somewhere.com', namespace.href) end def test_find_ns_by_href node = @doc.find_first('//ns1:getManufacturerNamesResponse', :ns1 => 'http://services.somewhere.com') namespace = node.namespaces.find_by_href('http://schemas.xmlsoap.org/soap/envelope/') assert_instance_of(LibXML::XML::Namespace, namespace) assert_equal('soap', namespace.prefix) assert_equal('http://schemas.xmlsoap.org/soap/envelope/', namespace.href) end def test_default_namespace doc = LibXML::XML::Document.string('') ns = doc.root.namespaces.default assert_equal(ns.href, 'http://schemas.xmlsoap.org/soap/envelope/') end def test_default_prefix doc = LibXML::XML::Document.string('') doc.root.namespaces.default_prefix = 'soap' node = doc.root.find_first('/soap:Envelope') refute_nil(node) end end libxml-ruby-5.0.3/test/test_error.rb0000644000004100000410000001403214620142101017500 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' require 'stringio' class TestError < Minitest::Test def test_error_codes assert_equal(4, LibXML::XML::Error::DTD) assert_equal(4, LibXML::XML::Error.const_get('DTD')) assert_equal(4, LibXML::XML::Error::DOCUMENT_EMPTY) assert_equal(4, LibXML::XML::Error.const_get('DOCUMENT_EMPTY')) end def test_invalid_handler assert_raises(RuntimeError) do LibXML::XML::Error.set_handler end end def test_handler exception = nil LibXML::XML::Error.set_handler do |error| exception = error end # Raise the error error = assert_raises(LibXML::XML::Error) do LibXML::XML::Reader.string('').parse end ensure Object.const_set(:STDERR, original_stderr) end assert_equal("Fatal error: Opening and ending tag mismatch: foo line 1 and foz at :1.\n", output.string) end def test_no_handler LibXML::XML::Error.reset_handler output = StringIO.new original_stderr = Object::STDERR Object.const_set(:STDERR, output) begin assert_raises(LibXML::XML::Error) do LibXML::XML::Parser.string('').parse end ensure Object.const_set(:STDERR, original_stderr) end assert_equal('', output.string) end def test_parse_error exception = assert_raises(LibXML::XML::Error) do LibXML::XML::Parser.string('').parse end assert_instance_of(LibXML::XML::Error, exception) assert_equal("Fatal error: Opening and ending tag mismatch: foo line 1 and foz at :1.", exception.message) assert_equal(LibXML::XML::Error::PARSER, exception.domain) assert_equal(LibXML::XML::Error::TAG_NAME_MISMATCH, exception.code) assert_equal(LibXML::XML::Error::FATAL, exception.level) assert_nil(exception.file) assert_equal(1, exception.line) end def test_xpath_error doc = LibXML::XML::Document.file(File.join(File.dirname(__FILE__), 'model/soap.xml')) exception = assert_raises(LibXML::XML::Error) do doc.find('/foo[bar=test') end assert_instance_of(LibXML::XML::Error, exception) assert_equal("Error: Invalid predicate.", exception.message) assert_equal(LibXML::XML::Error::XPATH, exception.domain) assert_equal(LibXML::XML::Error::XPATH_INVALID_PREDICATE_ERROR, exception.code) assert_equal(LibXML::XML::Error::ERROR, exception.level) assert_nil(exception.file) assert_nil(nil) end def test_double_parse LibXML::XML::Error.set_handler {|msg| nil } parser = LibXML::XML::Parser.string("something") parser.parse error = assert_raises(LibXML::XML::Error) do # Try parsing a second time parser.parse end assert_equal(" LibXML::XML::Error.", error.to_s) end def test_double_parse_register_handler LibXML::XML::Parser.register_error_handler(lambda {|msg| nil }) parser = LibXML::XML::Parser.string("something") parser.parse error = assert_raises(LibXML::XML::Error) do # Try parsing a second time parser.parse end assert_equal(" LibXML::XML::Error.", error.to_s) end def test_libxml_parser_empty_string error = assert_raises(TypeError) do LibXML::XML::Parser.string(nil) end assert_equal('wrong argument type nil (expected String)', error.to_s) error = assert_raises(ArgumentError) do LibXML::XML::Parser.string("") end assert_equal('Must specify a string with one or more characters', error.to_s) end def test_error_domain_to_s exception = assert_raises(LibXML::XML::Error) do LibXML::XML::Parser.string('').parse end assert_equal(LibXML::XML::Error::PARSER, exception.domain) assert_equal("PARSER", exception.domain_to_s) end def test_error_code_to_s exception = assert_raises(LibXML::XML::Error) do LibXML::XML::Parser.string('').parse end assert_equal(LibXML::XML::Error::ENTITYREF_SEMICOL_MISSING, exception.code) assert_equal("ENTITYREF_SEMICOL_MISSING", exception.code_to_s) end end libxml-ruby-5.0.3/test/test_properties.rb0000644000004100000410000000177414620142101020554 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' # attributes is deprecated - use attributes instead. # Tests for backwards compatibility class Testattributes < Minitest::Test def setup() xp = LibXML::XML::Parser.string('onetwo') @doc = xp.parse end def teardown() @doc = nil end def test_traversal attributes = @doc.root.attributes assert_instance_of(LibXML::XML::Attributes, attributes) attribute = attributes.first assert_equal('uga', attribute.name) assert_equal('booga', attribute.value) attribute = attribute.next assert_instance_of(LibXML::XML::Attr, attribute) assert_equal('foo', attribute.name) assert_equal('bar', attribute.value) end def test_no_attributes attributes = @doc.root.child.attributes assert_instance_of(LibXML::XML::Attributes, attributes) assert_equal(0, attributes.length) end end libxml-ruby-5.0.3/test/test_parser.rb0000644000004100000410000002444514620142101017654 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' require 'stringio' class TestParser < Minitest::Test def setup LibXML::XML::Error.set_handler(&LibXML::XML::Error::QUIET_HANDLER) end # ----- Sources ------- def test_document file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.utf-8.xml')) parser = LibXML::XML::Parser.file(file) doc = parser.parse parser = LibXML::XML::Parser.document(doc) doc = parser.parse assert_instance_of(LibXML::XML::Document, doc) assert_instance_of(LibXML::XML::Parser::Context, parser.context) end def test_nil_document error = assert_raises(TypeError) do LibXML::XML::Parser.document(nil) end assert_equal("Must pass an LibXML::XML::Document object", error.message) end def test_file file = File.expand_path(File.join(File.dirname(__FILE__), 'model/rubynet.xml')) parser = LibXML::XML::Parser.file(file) doc = parser.parse assert_instance_of(LibXML::XML::Document, doc) assert_instance_of(LibXML::XML::Parser::Context, parser.context) end def test_noexistent_file error = assert_raises(LibXML::XML::Error) do LibXML::XML::Parser.file('i_dont_exist.xml') end assert_equal('Warning: failed to load external entity "i_dont_exist.xml".', error.message) end def test_nil_file error = assert_raises(TypeError) do LibXML::XML::Parser.file(nil) end assert_match(/nil into String/, error.message) end def test_file_encoding file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.utf-8.xml')) parser = LibXML::XML::Parser.file(file, :encoding => LibXML::XML::Encoding::ISO_8859_1) error = assert_raises(LibXML::XML::Error) do parser.parse end if windows? assert_match(/Fatal error: Opening and ending tag mismatch/, error.message) else assert_match(/Fatal error: Extra content at the end of the document/, error.message) end parser = LibXML::XML::Parser.file(file, :encoding => LibXML::XML::Encoding::UTF_8) doc = parser.parse refute_nil(doc) end def test_file_base_uri file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.utf-8.xml')) parser = LibXML::XML::Parser.file(file) doc = parser.parse assert(doc.child.base_uri.match(/test\/model\/bands.utf-8.xml/)) parser = LibXML::XML::Parser.file(file, :base_uri => "http://libxml.org") doc = parser.parse assert(doc.child.base_uri.match(/test\/model\/bands.utf-8.xml/)) end def test_io File.open(File.join(File.dirname(__FILE__), 'model/rubynet.xml')) do |io| parser = LibXML::XML::Parser.io(io) assert_instance_of(LibXML::XML::Parser, parser) doc = parser.parse assert_instance_of(LibXML::XML::Document, doc) assert_instance_of(LibXML::XML::Parser::Context, parser.context) end end def test_io_gc # Test that the reader keeps a reference # to the io object file = File.open(File.join(File.dirname(__FILE__), 'model/rubynet.xml')) parser = LibXML::XML::Parser.io(file) file = nil GC.start assert(parser.parse) end def test_nil_io error = assert_raises(TypeError) do LibXML::XML::Parser.io(nil) end assert_equal("Must pass in an IO object", error.message) end def test_string_io data = File.read(File.join(File.dirname(__FILE__), 'model/rubynet.xml')) string_io = StringIO.new(data) parser = LibXML::XML::Parser.io(string_io) doc = parser.parse assert_instance_of(LibXML::XML::Document, doc) assert_instance_of(LibXML::XML::Parser::Context, parser.context) end def test_string_io_thread thread = Thread.new do data = File.read(File.join(File.dirname(__FILE__), 'model/rubynet.xml')) string_io = StringIO.new(data) parser = LibXML::XML::Parser.io(string_io) doc = parser.parse assert_instance_of(LibXML::XML::Document, doc) assert_instance_of(LibXML::XML::Parser::Context, parser.context) end thread.join assert(true) puts 'Thread completed' end def test_string str = 'onetwo' parser = LibXML::XML::Parser.string(str) assert_instance_of(LibXML::XML::Parser, parser) doc = parser.parse assert_instance_of(LibXML::XML::Document, doc) assert_instance_of(LibXML::XML::Parser::Context, parser.context) end def test_nil_string error = assert_raises(TypeError) do LibXML::XML::Parser.string(nil) end assert_equal("wrong argument type nil (expected String)", error.message) end def test_string_options xml = <<-EOS ]> &foo; EOS # Parse normally - entities won't be substituted parser = LibXML::XML::Parser.string(xml) doc = parser.parse assert_nil(doc.child.base_uri) # Cdata section should be cdata nodes node = doc.find_first('/test/cdata').child assert_equal(LibXML::XML::Node::CDATA_SECTION_NODE, node.node_type) # Entities should not be substituted node = doc.find_first('/test/entity') assert_equal('&foo;', node.child.to_s) # Parse with options parser = LibXML::XML::Parser.string(xml, base_uri: 'http://libxml.rubyforge.org', options: LibXML::XML::Parser::Options::NOCDATA | LibXML::XML::Parser::Options::NOENT) doc = parser.parse assert_equal(doc.child.base_uri, 'http://libxml.rubyforge.org') # Cdata section should be text nodes node = doc.find_first('/test/cdata').child assert_equal(LibXML::XML::Node::TEXT_NODE, node.node_type) # Entities should be subtituted node = doc.find_first('/test/entity') assert_equal('bar', node.child.to_s) end def test_string_encoding # ISO_8859_1: # ö - f6 in hex, \366 in octal # ü - fc in hex, \374 in octal xml = <<-EOS m\366tley_cr\374e EOS # Parse as UTF_8 parser = LibXML::XML::Parser.string(xml, :encoding => LibXML::XML::Encoding::UTF_8) error = assert_raises(LibXML::XML::Error) do parser.parse end assert_equal("Fatal error: Input is not proper UTF-8, indicate encoding !\nBytes: 0xF6 0x74 0x6C 0x65 at :2.", error.message) # Parse as ISO_8859_1: parser = LibXML::XML::Parser.string(xml, :encoding => LibXML::XML::Encoding::ISO_8859_1) doc = parser.parse node = doc.find_first('//metal') assert_equal(Encoding::UTF_8, node.content.encoding) assert_equal("m\303\266tley_cr\303\274e", node.content) end def test_fd_gc # Test opening # of documents up to the file limit for the OS. # Ideally it should run until libxml emits a warning, # thereby knowing we've done a GC sweep. For the time being, # re-open the same doc `limit descriptors` times. # If we make it to the end, then we've succeeded, # otherwise an exception will be thrown. LibXML::XML::Error.set_handler {|error|} max_fd = if RUBY_PLATFORM.match(/mswin32|mswin64|mingw/i) 500 else Process.getrlimit(Process::RLIMIT_NOFILE)[0] + 1 end file = File.join(File.dirname(__FILE__), 'model/rubynet.xml') max_fd.times do LibXML::XML::Parser.file(file).parse end LibXML::XML::Error.reset_handler {|error|} end def test_open_many_files file = File.expand_path(File.join(File.dirname(__FILE__), 'model/atom.xml')) 1000.times do LibXML::XML::Parser.file(file).parse end end # ----- Errors ------ def test_error error = assert_raises(LibXML::XML::Error) do LibXML::XML::Parser.string('').parse end refute_nil(error) assert_kind_of(LibXML::XML::Error, error) assert_equal("Fatal error: Opening and ending tag mismatch: foo line 1 and foz at :1.", error.message) assert_equal(LibXML::XML::Error::PARSER, error.domain) assert_equal(LibXML::XML::Error::TAG_NAME_MISMATCH, error.code) assert_equal(LibXML::XML::Error::FATAL, error.level) assert_nil(error.file) assert_equal(1, error.line) assert_equal('foo', error.str1) assert_equal('foz', error.str2) assert_nil(error.str3) assert_equal(1, error.int1) assert([18, 20].include?(error.int2)) assert_nil(error.node) end def test_bad_xml parser = LibXML::XML::Parser.string('onetwo') error = assert_raises(LibXML::XML::Error) do refute_nil(parser.parse) end refute_nil(error) assert_kind_of(LibXML::XML::Error, error) if windows? assert_equal("Fatal error: Couldn't find end of Start Tag ruby_array line 1 at :1.", error.message) assert_equal(LibXML::XML::Error::GT_REQUIRED, error.code) assert_equal("ruby_array", error.str1) assert_equal(1, error.int1) else assert_equal("Fatal error: Extra content at the end of the document at :1.", error.message) assert_equal(LibXML::XML::Error::DOCUMENT_END, error.code) assert_nil(error.str1) assert_equal(0, error.int1) end assert_equal(LibXML::XML::Error::PARSER, error.domain) assert_equal(LibXML::XML::Error::FATAL, error.level) assert_nil(error.file) assert_equal(1, error.line) assert_nil(error.str2) assert_nil(error.str3) assert_equal(34, error.int2) assert_nil(error.node) end def test_errors_from_background_thread errors = [] background_errors = [] begin LibXML::XML::Error.set_handler do |error| errors << error end parser = LibXML::XML::Parser.string("") thread = Thread.new do LibXML::XML::Error.set_handler do |error| background_errors << error end parser.parse rescue nil end thread.join ensure LibXML::XML::Error.set_handler(&LibXML::XML::Error::QUIET_HANDLER) end assert_equal(errors.size, 0) assert_equal(background_errors.size, 1) end end libxml-ruby-5.0.3/test/test_attr.rb0000644000004100000410000001317314620142101017326 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class AttrNodeTest < Minitest::Test def setup xp = LibXML::XML::Parser.string(<<-EOS) City EOS @doc = xp.parse end def teardown @doc = nil end def city_member @doc.find('/city:CityModel/city:cityMember').first end def test_doc refute_nil(@doc) assert_equal(LibXML::XML::Encoding::NONE, @doc.encoding) end def test_types attribute = city_member.attributes.get_attribute('name') assert_instance_of(LibXML::XML::Attr, attribute) assert_equal('attribute', attribute.node_type_name) end def test_name attribute = city_member.attributes.get_attribute('name') assert_equal('name', attribute.name) assert_equal(Encoding::UTF_8, attribute.name.encoding) attribute = city_member.attributes.get_attribute('href') assert_equal('href', attribute.name) assert_equal('xlink', attribute.ns.prefix) assert_equal('http://www.w3.org/1999/xlink', attribute.ns.href) attribute = city_member.attributes.get_attribute_ns('http://www.w3.org/1999/xlink', 'href') assert_equal('href', attribute.name) assert_equal('xlink', attribute.ns.prefix) assert_equal('http://www.w3.org/1999/xlink', attribute.ns.href) end def test_value attribute = city_member.attributes.get_attribute('name') assert_equal('Cambridge', attribute.value) assert_equal(Encoding::UTF_8, attribute.value.encoding) attribute = city_member.attributes.get_attribute('href') assert_equal('http://www.foo.net/cgi-bin/wfs?FeatureID=C10239', attribute.value) end def test_set_value attribute = city_member.attributes.get_attribute('name') attribute.value = 'London' assert_equal('London', attribute.value) assert_equal(Encoding::UTF_8, attribute.value.encoding) attribute = city_member.attributes.get_attribute('href') attribute.value = 'http://i.have.changed' assert_equal('http://i.have.changed', attribute.value) assert_equal(Encoding::UTF_8, attribute.value.encoding) end def test_set_nil attribute = city_member.attributes.get_attribute('name') assert_raises(TypeError) do attribute.value = nil end end def test_create attributes = city_member.attributes assert_equal(5, attributes.length) attr = LibXML::XML::Attr.new(city_member, 'size', '50,000') assert_instance_of(LibXML::XML::Attr, attr) attributes = city_member.attributes assert_equal(6, attributes.length) assert_equal(attributes['size'], '50,000') end def test_create_on_node attributes = city_member.attributes assert_equal(5, attributes.length) attributes['country'] = 'England' attributes = city_member.attributes assert_equal(6, attributes.length) assert_equal(attributes['country'], 'England') end def test_create_ns assert_equal(5, city_member.attributes.length) ns = LibXML::XML::Namespace.new(city_member, 'my_namepace', 'http://www.mynamespace.com') attr = LibXML::XML::Attr.new(city_member, 'rating', 'rocks', ns) assert_instance_of(LibXML::XML::Attr, attr) assert_equal('rating', attr.name) assert_equal('rocks', attr.value) attributes = city_member.attributes assert_equal(6, attributes.length) assert_equal('rocks', city_member['rating']) end def test_remove attributes = city_member.attributes assert_equal(5, attributes.length) attribute = attributes.get_attribute('name') refute_nil(attribute.parent) assert(attribute.parent?) attribute.remove! assert_equal(4, attributes.length) attribute = attributes.get_attribute('name') assert_nil(attribute) end def test_first attribute = city_member.attributes.first assert_instance_of(LibXML::XML::Attr, attribute) assert_equal('name', attribute.name) assert_equal('Cambridge', attribute.value) attribute = attribute.next assert_instance_of(LibXML::XML::Attr, attribute) assert_equal('type', attribute.name) assert_equal('simple', attribute.value) attribute = attribute.next assert_instance_of(LibXML::XML::Attr, attribute) assert_equal('title', attribute.name) assert_equal('Trinity Lane', attribute.value) attribute = attribute.next assert_instance_of(LibXML::XML::Attr, attribute) assert_equal('href', attribute.name) assert_equal('http://www.foo.net/cgi-bin/wfs?FeatureID=C10239', attribute.value) attribute = attribute.next assert_instance_of(LibXML::XML::Attr, attribute) assert_equal('remoteSchema', attribute.name) assert_equal("city.xsd#xpointer(//complexType[@name='RoadType'])", attribute.value) attribute = attribute.next assert_nil(attribute) end def test_no_attributes element = @doc.find('/city:CityModel/city:type').first refute_nil(element.attributes) assert_equal(0, element.attributes.length) end endlibxml-ruby-5.0.3/test/test_encoding.rb0000644000004100000410000001115214620142101020135 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' # Code UTF8 Latin1 Hex # m 109 109 6D # ö 195 182 246 C3 B6 / F6 # t 116 116 74 # l 108 108 6C # e 101 101 65 # y 121 121 79 # _ 95 95 5F # c 99 99 63 # r 114 114 72 # ü 195 188 252 C3 BC / FC # e 101 101 65 # See: # http://en.wikipedia.org/wiki/ISO/IEC_8859-1 # http://en.wikipedia.org/wiki/List_of_Unicode_characters class TestEncoding < Minitest::Test def setup @original_encoding = Encoding.default_internal Encoding.default_internal = nil end def teardown Encoding.default_internal = @original_encoding end def file_for_encoding(encoding) file_name = "model/bands.#{encoding.name.downcase}.xml" File.join(File.dirname(__FILE__), file_name) end def load_encoding(encoding) @encoding = encoding file = file_for_encoding(encoding) @doc = LibXML::XML::Document.file(file, options: LibXML::XML::Parser::Options::NOBLANKS) end def test_encoding doc = LibXML::XML::Document.new assert_equal(LibXML::XML::Encoding::NONE, doc.encoding) assert_equal(Encoding::ASCII_8BIT, doc.rb_encoding) file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.xml')) doc = LibXML::XML::Document.file(file) assert_equal(LibXML::XML::Encoding::UTF_8, doc.encoding) assert_equal(Encoding::UTF_8, doc.rb_encoding) doc.encoding = LibXML::XML::Encoding::ISO_8859_1 assert_equal(LibXML::XML::Encoding::ISO_8859_1, doc.encoding) assert_equal(Encoding::ISO8859_1, doc.rb_encoding) end def test_no_internal_encoding_iso_8859_1 load_encoding(Encoding::ISO_8859_1) node = @doc.root.children.first name = node.name assert_equal(Encoding::UTF_8, name.encoding) assert_equal("m\u00F6tley_cr\u00FCe", name) assert_equal("109 195 182 116 108 101 121 95 99 114 195 188 101", name.bytes.to_a.join(" ")) assert_equal("M\u00F6tley Cr\u00FCe is an American heavy metal band formed in Los Angeles, California in 1981.", node.content) name = name.encode(Encoding::ISO_8859_1) assert_equal(Encoding::ISO_8859_1, name.encoding) assert_equal("m\xF6tley_cr\xFCe".force_encoding(Encoding::ISO_8859_1), name) assert_equal("109 246 116 108 101 121 95 99 114 252 101", name.bytes.to_a.join(" ")) assert_equal("M\xF6tley Cr\xFCe is an American heavy metal band formed in Los Angeles, California in 1981.".force_encoding(Encoding::ISO_8859_1), node.content.encode(Encoding::ISO_8859_1)) end def test_internal_encoding_iso_8859_1 Encoding.default_internal = Encoding::ISO_8859_1 load_encoding(Encoding::ISO_8859_1) node = @doc.root.children.first name = node.name assert_equal(Encoding::ISO_8859_1, name.encoding) assert_equal("109 246 116 108 101 121 95 99 114 252 101", name.bytes.to_a.join(" ")) assert_equal("m\xF6tley_cr\xFCe".force_encoding(Encoding::ISO_8859_1), name) assert_equal("109 246 116 108 101 121 95 99 114 252 101", name.bytes.to_a.join(" ")) assert_equal("M\xF6tley Cr\xFCe is an American heavy metal band formed in Los Angeles, California in 1981.".force_encoding(Encoding::ISO_8859_1), node.content.encode(Encoding::ISO_8859_1)) end def test_no_internal_encoding_utf_8 load_encoding(Encoding::UTF_8) node = @doc.root.children.first name = node.name assert_equal(@encoding, name.encoding) assert_equal("109 195 182 116 108 101 121 95 99 114 195 188 101", name.bytes.to_a.join(" ")) name = name.encode(Encoding::ISO_8859_1) assert_equal(Encoding::ISO_8859_1, name.encoding) assert_equal("109 246 116 108 101 121 95 99 114 252 101", name.bytes.to_a.join(" ")) end def test_internal_encoding_utf_8 Encoding.default_internal = Encoding::ISO_8859_1 load_encoding(Encoding::UTF_8) node = @doc.root.children.first name = node.name assert_equal(Encoding::ISO_8859_1, name.encoding) assert_equal("109 246 116 108 101 121 95 99 114 252 101", name.bytes.to_a.join(" ")) end def test_encoding_conversions assert_equal("UTF-8", LibXML::XML::Encoding.to_s(LibXML::XML::Encoding::UTF_8)) assert_equal(LibXML::XML::Encoding::UTF_8, LibXML::XML::Encoding.from_s("UTF-8")) end end libxml-ruby-5.0.3/test/test_html_parser.rb0000644000004100000410000001072314620142101020672 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' require 'stringio' class HTMLParserTest < Minitest::Test def html_file File.expand_path(File.join(File.dirname(__FILE__), 'model/ruby-lang.html')) end # ----- Sources ------ def test_file xp = LibXML::XML::HTMLParser.file(html_file) assert_instance_of(LibXML::XML::HTMLParser, xp) doc = xp.parse refute_nil(doc) end def test_noexistent_file error = assert_raises(LibXML::XML::Error) do LibXML::XML::HTMLParser.file('i_dont_exist.xml') end assert_equal('Warning: failed to load external entity "i_dont_exist.xml".', error.to_s) end def test_nil_file error = assert_raises(TypeError) do LibXML::XML::HTMLParser.file(nil) end assert_match(/nil into String/, error.to_s) end def test_io File.open(html_file) do |io| xp = LibXML::XML::HTMLParser.io(io) assert_instance_of(LibXML::XML::HTMLParser, xp) doc = xp.parse assert_instance_of(LibXML::XML::Document, doc) end end def test_io_gc # Test that the reader keeps a reference # to the io object file = File.open(html_file) parser = LibXML::XML::HTMLParser.io(file) file = nil GC.start assert(parser.parse) end def test_nil_io error = assert_raises(TypeError) do LibXML::XML::HTMLParser.io(nil) end assert_equal("Must pass in an IO object", error.to_s) end def test_string_io data = File.read(html_file) io = StringIO.new(data) xp = LibXML::XML::HTMLParser.io(io) assert_instance_of(LibXML::XML::HTMLParser, xp) doc = xp.parse assert_instance_of(LibXML::XML::Document, doc) end def test_string str = '

hi

' xp = LibXML::XML::HTMLParser.string(str) assert_instance_of(LibXML::XML::HTMLParser, xp) assert_instance_of(LibXML::XML::HTMLParser, xp) doc = xp.parse assert_instance_of(LibXML::XML::Document, doc) end def test_nil_string error = assert_raises(TypeError) do LibXML::XML::HTMLParser.string(nil) end assert_equal("wrong argument type nil (expected String)", error.to_s) end def test_parse html = <<-EOS Hello
World EOS parser = LibXML::XML::HTMLParser.string(html, :options => LibXML::XML::HTMLParser::Options::NOBLANKS) doc = parser.parse assert_instance_of LibXML::XML::Document, doc root = doc.root assert_instance_of LibXML::XML::Node, root assert_equal 'html', root.name head = root.child assert_instance_of LibXML::XML::Node, head assert_equal 'head', head.name meta = head.child assert_instance_of LibXML::XML::Node, meta assert_equal 'meta', meta.name assert_equal 'keywords', meta[:name] assert_equal 'nasty', meta[:content] body = head.next assert_instance_of LibXML::XML::Node, body assert_equal 'body', body.name hello = body.child # It appears that some versions of libxml2 add a layer of

# cant figure our why or how, so this skips it if there hello = hello.child if hello.name == "p" assert_instance_of LibXML::XML::Node, hello assert_equal 'Hello', hello.content br = hello.next assert_instance_of LibXML::XML::Node, br assert_equal 'br', br.name world = br.next assert_instance_of LibXML::XML::Node, world assert_equal 'World', world.content end def test_no_implied html = "hello world" parser = LibXML::XML::HTMLParser.string(html, :options => LibXML::XML::HTMLParser::Options::NOIMPLIED) doc = parser.parse assert_equal("

#{html}

", doc.root.to_s) end def test_comment doc = LibXML::XML::HTMLParser.string('', :options => LibXML::XML::HTMLParser::Options::NOIMPLIED | LibXML::XML::HTMLParser::Options::NOERROR | LibXML::XML::HTMLParser::Options::NOWARNING | LibXML::XML::HTMLParser::Options::RECOVER | LibXML::XML::HTMLParser::Options::NONET) assert(doc) end def test_open_many_files file = File.expand_path(File.join(File.dirname(__FILE__), 'model/ruby-lang.html')) 1000.times do LibXML::XML::HTMLParser.file(file).parse end end end libxml-ruby-5.0.3/test/test_sax_parser.rb0000644000004100000410000002622214620142101020522 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' require 'stringio' class DocTypeCallback include LibXML::XML::SaxParser::Callbacks def on_start_element(element, attributes) end end class TestCaseCallbacks include LibXML::XML::SaxParser::Callbacks attr_accessor :result def initialize @result = Array.new end def on_cdata_block(cdata) @result << "cdata: #{cdata}" end def on_characters(chars) @result << "characters: #{chars}" end def on_comment(text) @result << "comment: #{text}" end def on_end_document @result << "end_document" end def on_end_element(name) @result << "end_element: #{name}" end def on_end_element_ns(name, prefix, uri) @result << "end_element_ns #{name}, prefix: #{prefix}, uri: #{uri}" end # Called for parser errors. def on_error(error) @result << "error: #{error}" end def on_processing_instruction(target, data) @result << "pi: #{target} #{data}" end def on_start_document @result << "startdoc" end def on_start_element(name, attributes) attributes ||= Hash.new @result << "start_element: #{name}, attr: #{attributes.inspect}" end def on_start_element_ns(name, attributes, prefix, uri, namespaces) attributes ||= Hash.new namespaces ||= Hash.new @result << "start_element_ns: #{name}, attr: #{attributes.inspect}, prefix: #{prefix}, uri: #{uri}, ns: #{namespaces.inspect}" end end class TestSaxParser < Minitest::Test def saxtest_file File.join(File.dirname(__FILE__), 'model/atom.xml') end def verify(parser) result = parser.callbacks.result i = -1 assert_equal("startdoc", result[i+=1]) assert_equal("pi: xml-stylesheet type=\"text/xsl\" href=\"my_stylesheet.xsl\"", result[i+=1]) assert_equal("start_element: feed, attr: {}", result[i+=1]) assert_equal("start_element_ns: feed, attr: {}, prefix: , uri: http://www.w3.org/2005/Atom, ns: {nil=>\"http://www.w3.org/2005/Atom\"}", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("comment: Not a valid atom entry ", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("start_element: entry, attr: {}", result[i+=1]) assert_equal("start_element_ns: entry, attr: {}, prefix: , uri: http://www.w3.org/2005/Atom, ns: {}", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("start_element: title, attr: {\"type\"=>\"html\"}", result[i+=1]) assert_equal("start_element_ns: title, attr: {\"type\"=>\"html\"}, prefix: , uri: http://www.w3.org/2005/Atom, ns: {}", result[i+=1]) assert_equal("cdata: <>", result[i+=1]) assert_equal("end_element: title", result[i+=1]) assert_equal("end_element_ns title, prefix: , uri: http://www.w3.org/2005/Atom", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("start_element: content, attr: {\"type\"=>\"xhtml\"}", result[i+=1]) assert_equal("start_element_ns: content, attr: {\"type\"=>\"xhtml\"}, prefix: , uri: http://www.w3.org/2005/Atom, ns: {}", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("start_element: xhtml:div, attr: {}", result[i+=1]) assert_equal("start_element_ns: div, attr: {}, prefix: xhtml, uri: http://www.w3.org/1999/xhtml, ns: {\"xhtml\"=>\"http://www.w3.org/1999/xhtml\"}", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("start_element: xhtml:p, attr: {}", result[i+=1]) assert_equal("start_element_ns: p, attr: {}, prefix: xhtml, uri: http://www.w3.org/1999/xhtml, ns: {}", result[i+=1]) assert_equal("characters: hi there", result[i+=1]) assert_equal("end_element: xhtml:p", result[i+=1]) assert_equal("end_element_ns p, prefix: xhtml, uri: http://www.w3.org/1999/xhtml", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("end_element: xhtml:div", result[i+=1]) assert_equal("end_element_ns div, prefix: xhtml, uri: http://www.w3.org/1999/xhtml", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("end_element: content", result[i+=1]) assert_equal("end_element_ns content, prefix: , uri: http://www.w3.org/2005/Atom", result[i+=1]) assert_equal("characters: \n ", result[i+=1]) assert_equal("end_element: entry", result[i+=1]) assert_equal("end_element_ns entry, prefix: , uri: http://www.w3.org/2005/Atom", result[i+=1]) assert_equal("characters: \n", result[i+=1]) assert_equal("end_element: feed", result[i+=1]) assert_equal("end_element_ns feed, prefix: , uri: http://www.w3.org/2005/Atom", result[i+=1]) assert_equal("end_document", result[i+=1]) end def test_file parser = LibXML::XML::SaxParser.file(saxtest_file) parser.callbacks = TestCaseCallbacks.new parser.parse verify(parser) end def test_file_no_callbacks parser = LibXML::XML::SaxParser.file(saxtest_file) assert_equal true, parser.parse end def test_noexistent_file error = assert_raises(LibXML::XML::Error) do LibXML::XML::SaxParser.file('i_dont_exist.xml') end assert_equal('Warning: failed to load external entity "i_dont_exist.xml".', error.to_s) end def test_nil_file error = assert_raises(TypeError) do LibXML::XML::SaxParser.file(nil) end assert_match(/nil into String/, error.to_s) end def test_io File.open(saxtest_file) do |file| parser = LibXML::XML::SaxParser.io(file) parser.callbacks = TestCaseCallbacks.new parser.parse verify(parser) end end def test_nil_io error = assert_raises(TypeError) do LibXML::XML::HTMLParser.io(nil) end assert_equal("Must pass in an IO object", error.to_s) end def test_string_no_callbacks xml = File.read(saxtest_file) parser = LibXML::XML::SaxParser.string(xml) assert_equal true, parser.parse end def test_string xml = File.read(saxtest_file) parser = LibXML::XML::SaxParser.string(xml) parser.callbacks = TestCaseCallbacks.new parser.parse verify(parser) end def test_string_io xml = File.read(saxtest_file) io = StringIO.new(xml) parser = LibXML::XML::SaxParser.io(io) parser.callbacks = TestCaseCallbacks.new parser.parse verify(parser) end def test_nil_string error = assert_raises(TypeError) do LibXML::XML::SaxParser.string(nil) end assert_equal("wrong argument type nil (expected String)", error.to_s) end def test_doctype xml = <<-EOS a1 EOS parser = LibXML::XML::SaxParser.string(xml) parser.callbacks = DocTypeCallback.new doc = parser.parse refute_nil(doc) end def test_parse_warning # Two xml PIs is a warning xml = <<-EOS EOS parser = LibXML::XML::SaxParser.string(xml) parser.callbacks = TestCaseCallbacks.new parser.parse # Check callbacks result = parser.callbacks.result i = -1 assert_equal("startdoc", result[i+=1]) assert_equal("error: Warning: xmlParsePITarget: invalid name prefix 'xml' at :2.", result[i+=1]) assert_equal("pi: xml-invalid ", result[i+=1]) assert_equal("start_element: Test, attr: {}", result[i+=1]) assert_equal("start_element_ns: Test, attr: {}, prefix: , uri: , ns: {}", result[i+=1]) assert_equal("end_element: Test", result[i+=1]) assert_equal("end_element_ns Test, prefix: , uri: ", result[i+=1]) assert_equal("end_document", result[i+=1]) end def test_parse_error xml = <<-EOS EOS parser = LibXML::XML::SaxParser.string(xml) parser.callbacks = TestCaseCallbacks.new error = assert_raises(LibXML::XML::Error) do parser.parse end # Check callbacks result = parser.callbacks.result i = -1 base_err_msg = "Fatal error: (Premature end of data in tag Results line 1|EndTag: '<\\/' not found) at :2\\." re_err_msg1 = /\A(error: )#{base_err_msg}\z/ re_err_msg2 = /\A#{base_err_msg}\z/ assert_equal("startdoc", result[i+=1]) assert_equal("start_element: Results, attr: {}", result[i+=1]) assert_equal("start_element_ns: Results, attr: {}, prefix: , uri: , ns: {}", result[i+=1]) assert_equal("characters: \n", result[i+=1]) assert_match(re_err_msg1, result[i+=1]) assert_equal("end_document", result[i+=1]) refute_nil(error) assert_kind_of(LibXML::XML::Error, error) assert_match(re_err_msg2, error.message) assert_equal(LibXML::XML::Error::PARSER, error.domain) assert([LibXML::XML::Error::TAG_NOT_FINISHED, LibXML::XML::Error::LTSLASH_REQUIRED].include?(error.code)) assert_equal(LibXML::XML::Error::FATAL, error.level) assert_nil(error.file) assert_equal(2, error.line) # Sometimes this is nil and sometimes its not depending on OS and libxlm version # assert_nil(error.str1) assert_nil(error.str2) assert_nil(error.str3) assert([0, 1].include?(error.int1)) assert_equal(1, error.int2) assert_nil(error.node) end def test_parse_seg_fail xml = <<-EOS AQUALIA THERMAL Lichte cr├иme - Versterkende & kalmerende 24 u hydraterende verzorging
Huid wordt continu gehydrateerd, intens versterkt en gekalmeerd.
Hypoallergeen. Geschikt voor de gevoelige huid.

01.EFFECTIVITEIT
Intensief gehydrateerd, de huid voelt gekalmeerd. Ze voelt de hele dag soepel en fluweelzacht aan, zonder een trekkerig gevoel. De huid is elastischer, soepeler en stralender. Doeltreffendheid getest onder dermatologisch toezicht.

02.GEBRUIK
's Morgens en/ of 's avonds aanbrengen.

03.ACTIEVE INGREDIENTEN
Technologische innovatie: 24 u continue cellulaire vochtnevel. Voor de 1ste keer worden Thermaal Bronwater van Vichy, rijk aan zeldzame mineralen en Actief HyaluronineтДв verwerkt in microcapsules, die deze vervolgens verspreiden in de cellen.

04.TEXTUUR
De lichte cr├иme is verfrissend en trekt makkelijk in. Niet vet en niet kleverig. Zonder 'maskereffect'.

05.GEUR
Geparfumeerd

06.INHOUD
40 ml tube
EOS parser = LibXML::XML::SaxParser.string(xml) parser.callbacks = TestCaseCallbacks.new error = assert_raises(LibXML::XML::Error) do parser.parse end assert_match("Fatal error: xmlParseEntityRef: no name at", error.to_s) # Check callbacks parser.callbacks.result end end libxml-ruby-5.0.3/test/test_attr_decl.rb0000644000004100000410000000744414620142101020321 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class AttrDeclTest < Minitest::Test def setup xp = LibXML::XML::Parser.string(<<-EOS) ]> EOS @doc = xp.parse end def teardown @doc = nil end def test_attributes # Get a element with an access attribute elem = @doc.find_first('/root/property[@name="readonly"]') assert_equal(2, elem.attributes.length) refute_nil(elem['access']) # Get a element node without a access attribute elem = @doc.find_first('/root/property[@name="readwrite"]') assert_equal(1, elem.attributes.length) assert_nil(elem['access']) end def test_attr # Get a property node without a access attribute elem = @doc.find_first('/root/property[@name="readonly"]') # Get the attr_decl attr = elem.attributes.get_attribute('access') refute_nil(attr) assert_equal(LibXML::XML::Node::ATTRIBUTE_NODE, attr.node_type) assert_equal('attribute', attr.node_type_name) # Get its value assert_equal('r', attr.value) end def test_attr_decl # Get a property node without a access attribute elem = @doc.find_first('/root/property[@name="readwrite"]') # Get the attr_decl attr_decl = elem.attributes.get_attribute('access') refute_nil(attr_decl) assert_equal(LibXML::XML::Node::ATTRIBUTE_DECL, attr_decl.node_type) assert_equal('attribute declaration', attr_decl.node_type_name) # Get its value assert_equal('rw', attr_decl.value) end def test_type # Get a property node without a access attribute elem = @doc.find_first('/root/property[@name="readwrite"]') attr_decl = elem.attributes.get_attribute('access') refute_nil(attr_decl) assert_equal(LibXML::XML::Node::ATTRIBUTE_DECL, attr_decl.node_type) assert_equal('attribute declaration', attr_decl.node_type_name) end def test_name elem = @doc.find_first('/root/property[@name="readwrite"]') attr_decl = elem.attributes.get_attribute('access') assert_equal('access', attr_decl.name) end def test_value elem = @doc.find_first('/root/property[@name="readwrite"]') attr_decl = elem.attributes.get_attribute('access') assert_equal('rw', attr_decl.value) end def test_to_s elem = @doc.find_first('/root/property[@name="readwrite"]') attr_decl = elem.attributes.get_attribute('access') assert_equal('access = rw', attr_decl.to_s) end def test_prev elem = @doc.find_first('/root/property[@name="readwrite"]') attr_decl = elem.attributes.get_attribute('access') first_decl = attr_decl.prev assert_equal(LibXML::XML::Node::ATTRIBUTE_DECL, first_decl.node_type) assert_equal('name', first_decl.name) assert_nil(first_decl.value) elem_decl = first_decl.prev assert_equal(LibXML::XML::Node::ELEMENT_DECL, elem_decl.node_type) end def test_next elem = @doc.find_first('/root/property[@name="readwrite"]') attr_decl = elem.attributes.get_attribute('access') next_decl = attr_decl.next assert_nil(next_decl) end def test_doc elem = @doc.find_first('/root/property[@name="readwrite"]') attr_decl = elem.attributes.get_attribute('access') assert_same(@doc, attr_decl.doc) end def test_parent elem = @doc.find_first('/root/property[@name="readwrite"]') attr_decl = elem.attributes.get_attribute('access') parent = attr_decl.parent assert_instance_of(LibXML::XML::Dtd, parent) end endlibxml-ruby-5.0.3/test/test_xinclude.rb0000644000004100000410000000126614620142101020167 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestXInclude < Minitest::Test def setup @doc = LibXML::XML::Document.file(File.join(File.dirname(__FILE__), 'model/xinclude.xml')) assert_instance_of(LibXML::XML::Document, @doc) end def teardown @doc = nil end def test_ruby_xml_xinclude assert_equal(1, @doc.xinclude) assert_equal("\n\n

This libxml2 binding has the following project information:\n This is some text to include in an xml file via XInclude.

\n
\n", @doc.to_s) end end libxml-ruby-5.0.3/test/test_relaxng.rb0000644000004100000410000000273514620142101020016 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestRelaxNG < Minitest::Test def setup file = File.join(File.dirname(__FILE__), 'model/shiporder.xml') @doc = LibXML::XML::Document.file(file) end def teardown @doc = nil end def relaxng document = LibXML::XML::Document.file(File.join(File.dirname(__FILE__), 'model/shiporder.rng')) LibXML::XML::RelaxNG.document(document) end def test_from_doc assert_instance_of(LibXML::XML::RelaxNG, relaxng) end def test_valid assert(@doc.validate_relaxng(relaxng)) end def test_invalid new_node = LibXML::XML::Node.new('invalid', 'this will mess up validation') @doc.root << new_node error = assert_raises(LibXML::XML::Error) do @doc.validate_relaxng(relaxng) end refute_nil(error) assert_kind_of(LibXML::XML::Error, error) assert(error.message.match(/Error: Did not expect element invalid there/)) assert_equal(LibXML::XML::Error::RELAXNGV, error.domain) assert_equal(LibXML::XML::Error::LT_IN_ATTRIBUTE, error.code) assert_equal(LibXML::XML::Error::ERROR, error.level) assert(error.file.match(/shiporder\.xml/)) assert_nil(error.line) assert_equal('invalid', error.str1) assert_nil(error.str2) assert_nil(error.str3) assert_equal(0, error.int1) assert_equal(0, error.int2) refute_nil(error.node) assert_equal('invalid', error.node.name) end end libxml-ruby-5.0.3/test/test_xpath.rb0000644000004100000410000002024614620142101017477 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' require 'tempfile' class TestXPath < Minitest::Test def setup @doc = LibXML::XML::Document.file(File.join(File.dirname(__FILE__), 'model/soap.xml')) end def teardown @doc = nil end def test_doc_find nodes = @doc.find('/soap:Envelope') assert_instance_of(LibXML::XML::XPath::Object, nodes) assert_equal(1, nodes.length) assert_equal(nodes.xpath_type, LibXML::XML::XPath::NODESET) end def test_doc_find_first node = @doc.find_first('/soap:Envelope/soap:Body') assert_instance_of(LibXML::XML::Node, node) end def test_ns nodes = @doc.find('//ns1:IdAndName', 'ns1:http://domain.somewhere.com') assert_equal(3, nodes.length) end def test_ns_gc _stress = GC.stress GC.stress = true doc = LibXML::XML::Document.string('') node = doc.root # This line segfaults on prior versions of libxml-ruby node.find("namespace::*") GC.stress = _stress end def test_ns_array nodes = @doc.find('//ns1:IdAndName', ['ns1:http://domain.somewhere.com']) assert_equal(3, nodes.length) end def test_default_ns1 # Find all nodes with http://services.somewhere.com namespace nodes = @doc.find('//*[namespace-uri()="http://services.somewhere.com"]') assert_equal(2, nodes.length) assert_equal('getManufacturerNamesResponse', nodes[0].name) assert_equal('IDAndNameList', nodes[1].name) end def test_default_ns2 # Find all nodes with http://services.somewhere.com namespace nodes = @doc.find('//ns:*', 'ns:http://services.somewhere.com') assert_equal(2, nodes.length) assert_equal('getManufacturerNamesResponse', nodes[0].name) assert_equal('IDAndNameList', nodes[1].name) # Get getManufacturerNamesResponse node nodes = @doc.find('//ns:getManufacturerNamesResponse', 'ns:http://services.somewhere.com') assert_equal(1, nodes.length) # Get IdAndName node nodes = @doc.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse/ns0:IDAndNameList/ns1:IdAndName', ['ns0:http://services.somewhere.com', 'ns1:http://domain.somewhere.com']) assert_equal(3, nodes.length) end def test_default_ns3 # Find all nodes with http://services.somewhere.com namespace nodes = @doc.find('//ns:*', 'ns' => 'http://services.somewhere.com') assert_equal(2, nodes.length) assert_equal('getManufacturerNamesResponse', nodes[0].name) assert_equal('IDAndNameList', nodes[1].name) end def test_default_ns4 # Find all nodes with http://services.somewhere.com namespace nodes = @doc.find('//ns:*', :ns => 'http://services.somewhere.com') assert_equal(2, nodes.length) assert_equal('getManufacturerNamesResponse', nodes[0].name) assert_equal('IDAndNameList', nodes[1].name) end def test_default_ns5 # Find all nodes with http://services.somewhere.com namespace LibXML::XML::Namespace.new(@doc.root, 'ns', 'http://services.somewhere.com') nodes = @doc.find('//ns:*') assert_equal(2, nodes.length) assert_equal('getManufacturerNamesResponse', nodes[0].name) assert_equal('IDAndNameList', nodes[1].name) end def test_attribute_ns # Pull all nodes with http://services.somewhere.com namespace nodes = @doc.find('@soap:encodingStyle') assert_equal(1, nodes.length) assert_equal('encodingStyle', nodes.first.name) assert_equal('http://www.w3.org/2001/12/soap-encoding', nodes.first.value) end def test_register_default_ns doc = LibXML::XML::Document.file(File.join(File.dirname(__FILE__), 'model/atom.xml')) # No namespace has been yet defined assert_raises(LibXML::XML::Error) do doc.find("atom:title") end node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom') refute_nil(node) # Register namespace doc.root.namespaces.default_prefix = 'atom' node = doc.find("atom:title") refute_nil(node) end def test_node_find nodes = @doc.find('//ns1:IdAndName', 'ns1:http://domain.somewhere.com') node = nodes.first # Since we are searching on the node, don't have to register namespace nodes = node.find('ns1:name') assert_equal(1, nodes.length) refute_equal(nodes.first.object_id, nodes.last.object_id) assert_equal('name', nodes.first.name) assert_equal('man1', nodes.first.content) end def test_node_find_first node = @doc.find_first('//ns1:IdAndName', 'ns1:http://domain.somewhere.com') # Since we are searching on the node, don't have to register namespace node = node.find_first('ns1:name') assert_equal('name', node.name) assert_equal('man1', node.content) end def test_node_no_doc node = LibXML::XML::Node.new('header', 'some content') assert_raises(TypeError) do node = node.find_first('/header') end end def test_memory # This sometimes causes a segmentation fault because # an xml document is sometimes freed before the # xpath_object used to query it. When the xpath_object # is free, it iterates over its results which are pointers # to the document's nodes. A segmentation fault then happens. 1000.times do doc = LibXML::XML::Document.new('1.0') doc.root = LibXML::XML::Node.new("header") 1000.times do doc.root << LibXML::XML::Node.new("footer") end doc.find('/header/footer') end end # Test that document doesn't get freed before nodes def test_xpath_free doc = LibXML::XML::Document.file(File.join(File.dirname(__FILE__), 'model/soap.xml')) nodes = doc.find('//*') GC.start assert_equal('Envelope', nodes.first.name) end def test_xpath_namespace_nodes doc = LibXML::XML::Document.string('') nodes = doc.find('//atom:entry|namespace::*', :atom => "http://www.w3.org/2005/Atom") assert_equal(4, nodes.length) node = nodes[0] assert_equal(LibXML::XML::Node::ELEMENT_NODE, node.node_type) node = nodes[1] assert_equal(LibXML::XML::Node::NAMESPACE_DECL, node.node_type) node = nodes[2] assert_equal(LibXML::XML::Node::NAMESPACE_DECL, node.node_type) node = nodes[3] assert_equal(LibXML::XML::Node::NAMESPACE_DECL, node.node_type) end # Test to make sure we don't get nil on empty results. # This is also to test that we don't segfault due to our C code getting a NULL pointer # and not handling it properly. def test_xpath_empty_result doc = LibXML::XML::Document.string('

Welcome to XHTML land!

') nodes = doc.find("//object/param[translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = 'wmode']") refute_nil nodes end def test_invalid_expression xml = LibXML::XML::Document.string('') # Using the expression twice used to cause a Segmentation Fault error = assert_raises(LibXML::XML::Error) do xml.find('//a/') end assert_equal("Error: Invalid expression.", error.to_s) # Try again - this used to cause a Segmentation Fault error = assert_raises(LibXML::XML::Error) do xml.find('//a/') end assert_equal("Error: Invalid expression.", error.to_s) end def test_find_cdata doc = LibXML::XML::Document.string('hi there bye!') nodes = doc.find('/root/text()') assert_equal(3, nodes.length) assert_equal(nodes[0].node_type, LibXML::XML::Node::TEXT_NODE) assert_equal(nodes[0].content, 'hi there ') assert_equal(nodes[1].node_type, LibXML::XML::Node::CDATA_SECTION_NODE) assert_equal(nodes[1].content, ' mycdata ') assert_equal(nodes[2].node_type, LibXML::XML::Node::TEXT_NODE) assert_equal(nodes[2].content, ' bye!') end def test_find_comment doc = LibXML::XML::Document.string('hi there bye!') nodes = doc.find('//comment()') assert_equal(1, nodes.length) assert_equal(nodes[0].content, ' my comment ') end end libxml-ruby-5.0.3/test/test_canonicalize.rb0000644000004100000410000001337414620142101021016 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class TestCanonicalize < Minitest::Test def path(file) File.join(File.dirname(__FILE__), file) end # (www.w3.org) 3.1 PIs, Comments, and Outside of Document Element # http://www.w3.org/TR/xml-c14n#Example-OutsideDoc def test_canonicalize_with_w3c_c14n_3_1 given_doc = LibXML::XML::Document.file(self.path('c14n/given/example-1.xml')) # With Comments expected_with_comments = IO.read(self.path('c14n/result/with-comments/example-1')) assert_equal(expected_with_comments, given_doc.canonicalize(:comments => true)) # Without Comments expected_without_comments = IO.read(self.path('c14n/result/without-comments/example-1')) assert_equal(expected_without_comments, given_doc.canonicalize) assert_equal(expected_without_comments, given_doc.canonicalize(:comments => false)) # Without Comments (XML_C14N_1_1) expected_1_1_without_comments = IO.read(self.path('c14n/result/1-1-without-comments/example-1')) mode = LibXML::XML::Document::XML_C14N_1_1 assert_equal(expected_1_1_without_comments, given_doc.canonicalize(:mode => mode)) end#test_canonicalize_with_w3c_c14n_3_1 # (www.w3.org) 3.2 Whitespace in Document Content # http://www.w3.org/TR/xml-c14n#Example-WhitespaceInContent def test_canonicalize_with_w3c_c14n_3_2 given_doc = LibXML::XML::Document.file(self.path('c14n/given/example-2.xml')) expected = IO.read(self.path('c14n/result/without-comments/example-2')) assert_equal(expected, given_doc.canonicalize) expected_1_1_without_comments = IO.read(self.path('c14n/result/1-1-without-comments/example-2')) mode = LibXML::XML::Document::XML_C14N_1_1 assert_equal(expected_1_1_without_comments, given_doc.canonicalize(:mode => mode)) end # (www.w3.org) 3.3 Start and End Tags # http://www.w3.org/TR/xml-c14n#Example-SETags # (2012-02-20) Test failing due to missing 'attr' in 'e9' node. # - Embedded DTD not parsed out of XML, therefore default attributes are # not applied to canonicalization. def test_canonicalize_with_w3c_c14n_3_3 given_doc = LibXML::XML::Document.file(self.path('c14n/given/example-3.xml')) expected = IO.read(self.path('c14n/result/without-comments/example-3')) assert_equal(expected, given_doc.canonicalize) expected_1_1_without_comments = IO.read(self.path('c14n/result/1-1-without-comments/example-3')) mode = LibXML::XML::Document::XML_C14N_1_1 assert_equal(expected_1_1_without_comments, given_doc.canonicalize(:mode => mode)) end # (www.w3.org) 3.4 Character Modifications and Character References # http://www.w3.org/TR/xml-c14n#Example-Chars def test_canonicalize_with_w3c_c14n_3_4 given_doc = LibXML::XML::Document.file(self.path('c14n/given/example-4.xml')) expected = IO.read(self.path('c14n/result/without-comments/example-4')) assert_equal(expected, given_doc.canonicalize) expected_1_1_without_comments = IO.read(self.path('c14n/result/1-1-without-comments/example-4')) mode = LibXML::XML::Document::XML_C14N_1_1 assert_equal(expected_1_1_without_comments, given_doc.canonicalize(:mode => mode)) end # (www.w3.org) 3.5 Entity References # http://www.w3.org/TR/xml-c14n#Example-Entities # (2012-02-20) Failing likely due to a logic error # - libxml2(c14n.c:1788) XML_ENTITY_REF_NODE is invalid node for parsing. def test_canonicalize_with_w3c_c14n_3_5 #given_doc = LibXML::XML::Document.file(self.path('c14n/given/example-5.xml')) # With Comments #expected_with_comments = IO.read(self.path('c14n/result/with-comments/example-5')) # TODO - CANNOT COMPLETE TEST unless libxml2 supports additional node types. #assert_equal(expected_with_comments, given_doc.canonicalize(:comments => true)) # Without Comments #expected_without_comments = IO.read(self.path('c14n/result/without-comments/example-5')) # TODO - CANNOT COMPLETE TEST unless libxml2 supports additional node types. #assert_equal(expected_without_comments, given_doc.canonicalize(:comments => false)) #expected_1_1_without_comments = IO.read(self.path('c14n/result/1-1-without-comments/example-5')) #mode = LibXML::XML::Document::XML_C14N_1_1 # TODO - CANNOT COMPLETE TEST unless libxml2 supports additional node types. #assert_equal(expected_1_1_without_comments, given_doc.canonicalize(:mode => mode)) end # (www.w3.org) 3.6 UTF-8 Encoding # http://www.w3.org/TR/xml-c14n#Example-UTF8 def test_canonicalize_with_w3c_c14n_3_6 given_doc = LibXML::XML::Document.file(self.path('c14n/given/example-6.xml')) expected = IO.read(self.path('c14n/result/without-comments/example-6'), :encoding => Encoding::UTF_8) assert_equal(expected, given_doc.canonicalize) expected_1_1_without_comments = IO.read(self.path('c14n/result/1-1-without-comments/example-6'), :encoding => Encoding::UTF_8) mode = LibXML::XML::Document::XML_C14N_1_1 assert_equal(expected_1_1_without_comments, given_doc.canonicalize(:mode => mode)) end # (www.w3.org) 3.7 Document Subsets # http://www.w3.org/TR/xml-c14n#Example-DocSubsets def test_canonicalize_with_w3c_c14n_3_7 # Non Canonicalized Document # given_doc = LibXML::XML::Document.file(self.path('c14n/given/example-7.xml')) #expected = IO.read(self.path('c14n/result/without-comments/example-7')) # e1_node = given_doc.find_first('ietf:e1', 'ietf:http://www.ietf.org') # Select current node, all child nodes, all attributes and namespace nodes #subdoc_nodes = e1_node.find("(.//.|.//@id|namespace::*)") # TODO - This fails because the namespace nodes aren't taken into account # assert_equal(expected, given_doc.canonicalize(:nodes => subdoc_nodes)) end end libxml-ruby-5.0.3/test/test_node_cdata.rb0000644000004100000410000000247414620142101020437 0ustar www-datawww-data# encoding: UTF-8 require_relative './test_helper' class CDataCommentTest < Minitest::Test def setup xp = LibXML::XML::Parser.string('') @doc = xp.parse assert_instance_of(LibXML::XML::Document, @doc) @root = @doc.root end def test_node_type cnode = LibXML::XML::Node.new_cdata('test cdata') assert_equal(LibXML::XML::Node::CDATA_SECTION_NODE, cnode.node_type) end def test_add_cdata @root << LibXML::XML::Node.new_cdata('mycdata') assert_equal '', @root.to_s.gsub(/\n\s*/,'') end def test_add_cdata_2 @root << LibXML::XML::Node.new_cdata('mycdata') assert_equal 'cdata', @root.child.node_type_name end def test_add_cdata_3 @root << el = LibXML::XML::Node.new_cdata('mycdata') el << "_this_is_added" assert_equal '', @root.to_s.gsub(/\n\s*/,'') end def test_attributes cnode = LibXML::XML::Node.new_cdata('test cdata') assert_equal(0, cnode.attributes.length) end def test_set_cdata_attribute cnode = LibXML::XML::Node.new_cdata('test cdata') # Can't create attributes on non-element nodes assert_raises(ArgumentError) do cnode['attr'] = '123' end end end libxml-ruby-5.0.3/Rakefile0000644000004100000410000000526014620142101015454 0ustar www-datawww-data#!/usr/bin/env ruby require "rubygems" require "rake/extensiontask" require "rake/testtask" require "rubygems/package_task" require "rdoc/task" require "yaml" GEM_NAME = "libxml-ruby" SO_NAME = "libxml_ruby" # Read the spec file spec = Gem::Specification.load("#{GEM_NAME}.gemspec") task :default => [:test] # Setup compile tasks Rake::ExtensionTask.new do |ext| ext.gem_spec = spec ext.name = SO_NAME ext.ext_dir = "ext/libxml" ext.lib_dir = "lib/#{RUBY_VERSION.sub(/\.\d$/, '')}" if RUBY_PLATFORM.match(/mswin|mingw/) ext.config_options << if (dir = ENV['WINDOWS_XML2_INCLUDE']) "--with-xml2-include=#{dir}" else case RUBY_PLATFORM when 'i386-mingw32' '--with-xml2-include=C:/msys64/mingw32/include/libxml2' when 'x64-mingw32' '--with-xml2-include=C:/msys64/mingw64/include/libxml2' when 'x64-mingw-ucrt' '--with-xml2-include=C:/msys64/ucrt64/include/libxml2' else raise "Unknown Windows Ruby, please set ENV['WINDOWS_XML2_INCLUDE']" end end else ext.config_options << '--with-xml2-include=/usr/include/libxml2' end end # Setup generic gem Gem::PackageTask.new(spec) do |pkg| pkg.package_dir = 'pkg' pkg.need_tar = false end # Setup Windows Gem if RUBY_PLATFORM.match(/mswin|mingw/) binaries = (FileList['lib/**/*.so', 'lib/**/*dll']) # Windows specification win_spec = spec.clone win_spec.platform = Gem::Platform::CURRENT win_spec.files += binaries.to_a win_spec.instance_variable_set(:@cache_file, nil) # Unset extensions win_spec.extensions = nil # Rake task to build the windows package Gem::PackageTask.new(win_spec) do |pkg| pkg.package_dir = 'pkg' pkg.need_tar = false end end # RDoc Task desc 'Generate rdoc documentation' RDoc::Task.new("rdoc") do |rdoc| rdoc.rdoc_dir = 'rdoc' rdoc.title = 'LibXML' rdoc.generator = 'hanna' # Show source inline with line numbers rdoc.options << '--line-numbers' rdoc.options << '--charset=utf-8' # Make the readme file the start page for the generated html rdoc.main = 'README.rdoc' rdoc.rdoc_files.include('doc/*.rdoc', 'ext/**/libxml.c', 'ext/**/ruby_xml.c', 'ext/**/*.c', 'lib/**/*.rb', 'README.rdoc', 'HISTORY', 'LICENSE') end # Test Task Rake::TestTask.new do |t| t.libs << "test" t.test_files = FileList['test/test*.rb'] - ['test/test_suite.rb'] t.verbose = true endlibxml-ruby-5.0.3/LICENSE0000644000004100000410000000227514620142101015017 0ustar www-datawww-data Copyright (c) 2008-2013 Charlie Savage and contributors Copyright (c) 2002-2007 Sean Chittenden and contributors Copyright (c) 2001 Wai-Sun "Squidster" Chia Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.libxml-ruby-5.0.3/ext/0000755000004100000410000000000014620142101014604 5ustar www-datawww-datalibxml-ruby-5.0.3/ext/libxml/0000755000004100000410000000000014620142101016073 5ustar www-datawww-datalibxml-ruby-5.0.3/ext/libxml/ruby_xml_parser_options.c0000644000004100000410000000654714620142101023243 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include #include "ruby_libxml.h" /* Document-class: LibXML::XML::Parser::Options * * Options that control the operation of the HTMLParser. The easiest * way to set a parser's options is to use the methods * XML::Parser.file, XML::Parser.io or XML::Parser.string. * For additional control, see XML::Parser::Context#options=. */ VALUE mXMLParserOptions; void rxml_init_parser_options(void) { mXMLParserOptions = rb_define_module_under(cXMLParser, "Options"); /* recover on errors */ rb_define_const(mXMLParserOptions, "RECOVER", INT2NUM(XML_PARSE_RECOVER)); /* substitute entities */ rb_define_const(mXMLParserOptions, "NOENT", INT2NUM(XML_PARSE_NOENT)); /* load the external subset */ rb_define_const(mXMLParserOptions, "DTDLOAD", INT2NUM(XML_PARSE_DTDLOAD)); /* default DTD attributes */ rb_define_const(mXMLParserOptions, "DTDATTR", INT2NUM(XML_PARSE_DTDATTR)); /* validate with the DTD */ rb_define_const(mXMLParserOptions, "DTDVALID", INT2NUM(XML_PARSE_DTDVALID)); /* suppress error reports */ rb_define_const(mXMLParserOptions, "NOERROR", INT2NUM(XML_PARSE_NOERROR)); /* suppress warning reports */ rb_define_const(mXMLParserOptions, "NOWARNING", INT2NUM(XML_PARSE_NOWARNING)); /* pedantic error reporting */ rb_define_const(mXMLParserOptions, "PEDANTIC", INT2NUM(XML_PARSE_PEDANTIC)); /* remove blank nodes */ rb_define_const(mXMLParserOptions, "NOBLANKS", INT2NUM(XML_PARSE_NOBLANKS)); /* use the SAX1 interface internally */ rb_define_const(mXMLParserOptions, "SAX1", INT2NUM(XML_PARSE_SAX1)); /* Implement XInclude substitition */ rb_define_const(mXMLParserOptions, "XINCLUDE", INT2NUM(XML_PARSE_XINCLUDE)); /* Forbid network access */ rb_define_const(mXMLParserOptions, "NONET", INT2NUM(XML_PARSE_NONET)); /* Do not reuse the context dictionnary */ rb_define_const(mXMLParserOptions, "NODICT", INT2NUM(XML_PARSE_NODICT)); /* remove redundant namespaces declarations */ rb_define_const(mXMLParserOptions, "NSCLEAN", INT2NUM(XML_PARSE_NSCLEAN)); /* merge CDATA as text nodes */ rb_define_const(mXMLParserOptions, "NOCDATA", INT2NUM(XML_PARSE_NOCDATA)); #if LIBXML_VERSION >= 20621 /* do not generate XINCLUDE START/END nodes */ rb_define_const(mXMLParserOptions, "NOXINCNODE", INT2NUM(XML_PARSE_NOXINCNODE)); #endif #if LIBXML_VERSION >= 20700 /* compact small text nodes */ rb_define_const(mXMLParserOptions, "COMPACT", INT2NUM(XML_PARSE_COMPACT)); /* parse using XML-1.0 before update 5 */ rb_define_const(mXMLParserOptions, "OLD10", INT2NUM(XML_PARSE_OLD10)); /* do not fixup XINCLUDE xml:base uris */ rb_define_const(mXMLParserOptions, "NOBASEFIX", INT2NUM(XML_PARSE_NOBASEFIX)); #endif #if LIBXML_VERSION >= 20703 /* relax any hardcoded limit from the parser */ rb_define_const(mXMLParserOptions, "HUGE", INT2NUM(XML_PARSE_HUGE)); #endif #if LIBXML_VERSION >= 21106 /* parse using SAX2 interface before 2.7.0 */ rb_define_const(mXMLParserOptions, "OLDSAX", INT2NUM(XML_PARSE_OLDSAX)); /* ignore internal document encoding hint */ rb_define_const(mXMLParserOptions, "IGNORE_ENC", INT2NUM(XML_PARSE_IGNORE_ENC)); /* Store big lines numbers in text PSVI field */ rb_define_const(mXMLParserOptions, "BIG_LINES", INT2NUM(XML_PARSE_BIG_LINES)); #endif } libxml-ruby-5.0.3/ext/libxml/ruby_xml_xpath_expression.c0000644000004100000410000000456314620142101023573 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_xpath.h" #include "ruby_xml_xpath_expression.h" /* * Document-class: LibXML::XML::XPath::Expression * * The XML::XPath::Expression class is used to compile * XPath expressions so they can be parsed only once * but reused multiple times. * * doc = XML::Document.string(IO.read('some xml file')) * expr = XPath::Expression.new('//first') * doc.root.each do |node| * result = node.find(expr) # many, many, many times * # ... * end */ VALUE cXMLXPathExpression; static void rxml_xpath_expression_free(xmlXPathCompExprPtr expr) { xmlXPathFreeCompExpr(expr); } static VALUE rxml_xpath_expression_alloc(VALUE klass) { return Data_Wrap_Struct(cXMLXPathExpression, NULL, rxml_xpath_expression_free, NULL); } /* call-seq: * XPath::Expression.compile(expression) -> XPath::Expression * * Compiles an XPath expression. This improves performance * when an XPath expression is called multiple times. * * doc = XML::Document.string('
hi
') * expr = XPath::Expression.new('//first') * nodes = doc.find(expr) */ static VALUE rxml_xpath_expression_compile(VALUE klass, VALUE expression) { VALUE args[] = {expression}; return rb_class_new_instance(1, args, cXMLXPathExpression); } /* call-seq: * XPath::Expression.new(expression) -> XPath::Expression * * Compiles an XPath expression. This improves performance * when an XPath expression is called multiple times. * * doc = XML::Document.string('
hi
') * expr = XPath::Expression.new('//first') * nodes = doc.find(expr) */ static VALUE rxml_xpath_expression_initialize(VALUE self, VALUE expression) { xmlXPathCompExprPtr compexpr = xmlXPathCompile((const xmlChar*)StringValueCStr(expression)); if (compexpr == NULL) { const xmlError *xerror = xmlGetLastError(); rxml_raise(xerror); } DATA_PTR( self) = compexpr; return self; } void rxml_init_xpath_expression(void) { cXMLXPathExpression = rb_define_class_under(mXPath, "Expression", rb_cObject); rb_define_alloc_func(cXMLXPathExpression, rxml_xpath_expression_alloc); rb_define_singleton_method(cXMLXPathExpression, "compile", rxml_xpath_expression_compile, 1); rb_define_method(cXMLXPathExpression, "initialize", rxml_xpath_expression_initialize, 1); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema_facet.c0000644000004100000410000000225714620142101022570 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_schema_facet.h" #include #include #include VALUE cXMLSchemaFacet; static void rxml_schema_facet_free(xmlSchemaFacetPtr xschema_type) { xschema_type = NULL; xmlFree(xschema_type); } VALUE rxml_wrap_schema_facet(xmlSchemaFacetPtr facet) { VALUE result; if (!facet) rb_raise(rb_eArgError, "XML::Schema::Facet required!"); result = Data_Wrap_Struct(cXMLSchemaFacet, NULL, rxml_schema_facet_free, facet); rb_iv_set(result, "@kind", INT2NUM(facet->type)); rb_iv_set(result, "@value", QNIL_OR_STRING(facet->value)); return result; } /* START FACET*/ static VALUE rxml_schema_facet_node(VALUE self) { xmlSchemaFacetPtr facet; Data_Get_Struct(self, xmlSchemaFacet, facet); return rxml_node_wrap(facet->node); } void rxml_init_schema_facet(void) { cXMLSchemaFacet = rb_define_class_under(cXMLSchema, "Facet", rb_cObject); rb_define_attr(cXMLSchemaFacet, "kind", 1, 0); rb_define_attr(cXMLSchemaFacet, "value", 1, 0); rb_define_method(cXMLSchemaFacet, "node", rxml_schema_facet_node, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_sax_parser.c0000644000004100000410000000566014620142101022336 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_sax_parser.h" /* * Document-class: LibXML::XML::SaxParser * * XML::SaxParser provides a callback based API for parsing documents, * in contrast to XML::Parser's tree based API and XML::Reader's stream * based API. * * The XML::SaxParser API is fairly complex, not well standardized, * and does not directly support validation making entity, namespace and * base processing relatively hard. * * To use the XML::SaxParser, register a callback class via the * XML::SaxParser#callbacks=. It is easiest to include the * XML::SaxParser::Callbacks module in your class and override * the methods as needed. * * Basic example: * * class MyCallbacks * include XML::SaxParser::Callbacks * def on_start_element(element, attributes) * puts #Element started: #{element}" * end * end * * parser = XML::SaxParser.string(my_string) * parser.callbacks = MyCallbacks.new * parser.parse * * You can also parse strings (see XML::SaxParser.string) and * io objects (see XML::SaxParser.io). */ VALUE cXMLSaxParser; static ID CALLBACKS_ATTR; static ID CONTEXT_ATTR; /* ====== Parser =========== */ /* * call-seq: * parser.initialize(context) -> XML::Parser * * Creates a new XML::Parser from the specified * XML::Parser::Context. */ static VALUE rxml_sax_parser_initialize(int argc, VALUE *argv, VALUE self) { VALUE context = Qnil; rb_scan_args(argc, argv, "01", &context); if (context == Qnil) { rb_raise(rb_eArgError, "An instance of a XML::Parser::Context must be passed to XML::SaxParser.new"); } rb_ivar_set(self, CONTEXT_ATTR, context); return self; } /* * call-seq: * parser.parse -> (true|false) * * Parse the input XML, generating callbacks to the object * registered via the +callbacks+ attributesibute. */ static VALUE rxml_sax_parser_parse(VALUE self) { VALUE context = rb_ivar_get(self, CONTEXT_ATTR); xmlParserCtxtPtr ctxt; Data_Get_Struct(context, xmlParserCtxt, ctxt); ctxt->sax2 = 1; ctxt->userData = (void*)rb_ivar_get(self, CALLBACKS_ATTR); memcpy(ctxt->sax, &rxml_sax_handler, sizeof(rxml_sax_handler)); int status = xmlParseDocument(ctxt); /* Now check the parsing result*/ if (status == -1 || !ctxt->wellFormed) { rxml_raise(&ctxt->lastError); } return Qtrue; } void rxml_init_sax_parser(void) { /* SaxParser */ cXMLSaxParser = rb_define_class_under(mXML, "SaxParser", rb_cObject); /* Atributes */ CALLBACKS_ATTR = rb_intern("@callbacks"); CONTEXT_ATTR = rb_intern("@context"); rb_define_attr(cXMLSaxParser, "callbacks", 1, 1); /* Instance Methods */ rb_define_method(cXMLSaxParser, "initialize", rxml_sax_parser_initialize, -1); rb_define_method(cXMLSaxParser, "parse", rxml_sax_parser_parse, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_node.h0000644000004100000410000000057514620142101021121 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_NODE__ #define __RXML_NODE__ extern VALUE cXMLNode; void rxml_init_node(void); void rxml_node_mark(xmlNodePtr xnode); VALUE rxml_node_wrap(xmlNodePtr xnode); void rxml_node_manage(xmlNodePtr xnode, VALUE node); void rxml_node_unmanage(xmlNodePtr xnode, VALUE node); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_document.c0000644000004100000410000007077614620142101022017 0ustar www-datawww-data/* * Document-class: LibXML::XML::Document * * The XML::Document class provides a tree based API for working * with xml documents. You may directly create a document and * manipulate it, or create a document from a data source by * using an XML::Parser object. * * To read a document from a file: * * doc = XML::Document.file('my_file') * * To use a parser to read a document: * * parser = XML::Parser.file('my_file') * doc = parser.parse * * To create a document from scratch: * * doc = XML::Document.new() * doc.root = XML::Node.new('root_node') * doc.root << XML::Node.new('elem1') * doc.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8) * * To write a document to a file: * * doc = XML::Document.new() * doc.root = XML::Node.new('root_node') * root = doc.root * * root << elem1 = XML::Node.new('elem1') * elem1['attr1'] = 'val1' * elem1['attr2'] = 'val2' * * root << elem2 = XML::Node.new('elem2') * elem2['attr1'] = 'val1' * elem2['attr2'] = 'val2' * * root << elem3 = XML::Node.new('elem3') * elem3 << elem4 = XML::Node.new('elem4') * elem3 << elem5 = XML::Node.new('elem5') * * elem5 << elem6 = XML::Node.new('elem6') * elem6 << 'Content for element 6' * * elem3['attr'] = 'baz' * * doc.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8) */ #include #include "ruby_libxml.h" #include "ruby_xml_document.h" #include #include #include #include #include VALUE cXMLDocument; void rxml_document_free(xmlDocPtr xdoc) { xdoc->_private = NULL; xmlFreeDoc(xdoc); } VALUE rxml_document_wrap(xmlDocPtr xdoc) { VALUE result = Qnil; // Is this node is already wrapped? if (xdoc->_private != NULL) { result = (VALUE)xdoc->_private; } else { result = Data_Wrap_Struct(cXMLDocument, NULL, rxml_document_free, xdoc); xdoc->_private = (void*)result; } return result; } /* * call-seq: * XML::Document.alloc(xml_version = 1.0) -> document * * Alocates a new XML::Document, optionally specifying the * XML version. */ static VALUE rxml_document_alloc(VALUE klass) { return Data_Wrap_Struct(klass, NULL, rxml_document_free, NULL); } /* * call-seq: * XML::Document.initialize(xml_version = 1.0) -> document * * Initializes a new XML::Document, optionally specifying the * XML version. */ static VALUE rxml_document_initialize(int argc, VALUE *argv, VALUE self) { xmlDocPtr xdoc; VALUE xmlver; switch (argc) { case 0: xmlver = rb_str_new2("1.0"); break; case 1: rb_scan_args(argc, argv, "01", &xmlver); break; default: rb_raise(rb_eArgError, "wrong number of arguments (need 0 or 1)"); } Check_Type(xmlver, T_STRING); xdoc = xmlNewDoc((xmlChar*) StringValuePtr(xmlver)); // Link the ruby object to the document and the document to the ruby object RDATA(self)->data = xdoc; xdoc->_private = (void*)self; return self; } /* XML_C14N_1* constants are not defined until libxml 1.1.25, so if they are not defined then define these constants to map to zero, the same value as XML_C14N_1_0. */ /* XML_C14N* constants are not defined until libxml 1.1.25, so define them if needed so things compile. */ #ifndef XML_C14N_1_0 #define XML_C14N_1_0 0 #define XML_C14N_EXCLUSIVE_1_0 XML_C14N_1_0 #define XML_C14N_1_1 XML_C14N_1_0 #endif /* * :call-seq: * document.canonicalize -> String * document.canonicalize(options) -> String * * Returns a string containing the canonicalized form of the document. * Implemented to include all of the functionality of the libxml2 * {xmlC14NDocDumpMemory}[http://xmlsoft.org/html/libxml-c14n.html#xmlC14NDocDumpMemory] * method. * * === Options * [comments] * * *Type:* Boolean * * *Default:* false * Specifies if comments should be output. * * Must be boolean, otherwise defaults to false. * [inclusive_ns_prefixes] * * *Type:* Array of strings * * *Default:* empty array * Array of namespace prefixes to include in exclusive canonicalization only. * * The last item in the list is reserved for a NULL value because the C method demands it, therefore * up to the first 255 valid entries will be used. * * Only used for *XML_C14N_EXCLUSIVE_1_0* mode. Ignored otherwise. * [mode] * * *Type:* XML::Document Constant * * *Default:* XML_C14N_1_0 * Specifies the mode of canonicalization. * * *NOTE:* XML_C14N_1_1 may not be fully implemented upon compilation due to C library compatibility. * Please check if XML_C14N_1_0 and XML_C14N_1_1 are the same value prior to using XML_C14N_1_1. * [nodes] * * *Type:* Array of XML::Node objects * * *Default:* empty array * XML::Nodes to include in the canonicalization process * * For large lists of more than 256 valid namespaces, up to the first 256 valid entries will be used. */ #define C14N_NS_LIMIT 256 #define C14N_NODESET_LIMIT 256 static VALUE rxml_document_canonicalize(int argc, VALUE *argv, VALUE self) { VALUE result = Qnil; xmlDocPtr xdoc; xmlChar *buffer = NULL; VALUE option_hash = Qnil; VALUE o_nodes = Qnil; // :comments option int comments = 0; // :mode option int c14n_mode = XML_C14N_1_0; // :inclusive_ns_prefixes option (ARRAY) xmlChar * inc_ns_prefixes_ptr[C14N_NS_LIMIT]; // :nodes option (ARRAY) xmlNodePtr node_ptr_array[C14N_NODESET_LIMIT]; xmlNodeSet nodeset = { 0, C14N_NODESET_LIMIT, NULL }; /* At least one NULL value must be defined in the array or the extension will * segfault when using XML_C14N_EXCLUSIVE_1_0 mode. * API docs: "list of inclusive namespace prefixes ended with a NULL" */ inc_ns_prefixes_ptr[0] = NULL; rb_scan_args(argc, argv, "01", &option_hash); // Do stuff if ruby hash passed as argument if (!NIL_P(option_hash)) { VALUE o_comments = Qnil; VALUE o_mode = Qnil; VALUE o_i_ns_prefixes = Qnil; Check_Type(option_hash, T_HASH); o_comments = rb_hash_aref(option_hash, ID2SYM(rb_intern("comments"))); comments = (RTEST(o_comments) ? 1 : 0); o_mode = rb_hash_aref(option_hash, ID2SYM(rb_intern("mode"))); if (!NIL_P(o_mode)) { Check_Type(o_mode, T_FIXNUM); c14n_mode = NUM2INT(o_mode); //TODO: clean this up //if (c14n_mode > 2) { c14n_mode = 0; } //mode_int = (NUM2INT(o_mode) > 2 ? 0 : NUM2INT(o_mode)); } o_i_ns_prefixes = rb_hash_aref(option_hash, ID2SYM(rb_intern("inclusive_ns_prefixes"))); if (!NIL_P(o_i_ns_prefixes)) { int i; int p = 0; //pointer array index VALUE *list_in = NULL; long list_size = 0; Check_Type(o_i_ns_prefixes, T_ARRAY); list_in = RARRAY_PTR(o_i_ns_prefixes); list_size = RARRAY_LEN(o_i_ns_prefixes); if (list_size > 0) { for(i=0; i < list_size; ++i) { if (p >= C14N_NS_LIMIT) { break; } if (RTEST(list_in[i])) { if (TYPE(list_in[i]) == T_STRING) { inc_ns_prefixes_ptr[p] = (xmlChar *)StringValueCStr(list_in[i]); p++; } } } } // ensure p is not out of bound p = (p >= C14N_NS_LIMIT ? (C14N_NS_LIMIT-1) : p); // API docs: "list of inclusive namespace prefixes ended with a NULL" // Set last element to NULL inc_ns_prefixes_ptr[p] = NULL; } //o_ns_prefixes will free at end of block o_nodes = rb_hash_aref(option_hash, ID2SYM(rb_intern("nodes"))); if (!NIL_P(o_nodes)) { int i; int p = 0; // index of pointer array VALUE * list_in = NULL; long node_list_size = 0; if (CLASS_OF(o_nodes) == cXMLXPathObject) { o_nodes = rb_funcall(o_nodes, rb_intern("to_a"), 0); } else { Check_Type(o_nodes, T_ARRAY); } list_in = RARRAY_PTR(o_nodes); node_list_size = RARRAY_LEN(o_nodes); for (i=0; i < node_list_size; ++i) { if (p >= C14N_NODESET_LIMIT) { break; } if (RTEST(list_in[i])) { xmlNodePtr node_ptr; Data_Get_Struct(list_in[i], xmlNode, node_ptr); node_ptr_array[p] = node_ptr; p++; } } // Need to set values in nodeset struct nodeset.nodeNr = (node_list_size > C14N_NODESET_LIMIT ? C14N_NODESET_LIMIT : (int)node_list_size); nodeset.nodeTab = node_ptr_array; } }//option_hash Data_Get_Struct(self, xmlDoc, xdoc); xmlC14NDocDumpMemory(xdoc, (nodeset.nodeNr == 0 ? NULL : &nodeset), c14n_mode, inc_ns_prefixes_ptr, comments, &buffer); if (buffer) { result = rxml_new_cstr( buffer, NULL); xmlFree(buffer); } return result; } /* * call-seq: * document.compression -> num * * Obtain this document's compression mode identifier. */ static VALUE rxml_document_compression_get(VALUE self) { #ifdef HAVE_ZLIB_H xmlDocPtr xdoc; int compmode; Data_Get_Struct(self, xmlDoc, xdoc); compmode = xmlGetDocCompressMode(xdoc); if (compmode == -1) return(Qnil); else return(INT2NUM(compmode)); #else rb_warn("libxml not compiled with zlib support"); return (Qfalse); #endif } /* * call-seq: * document.compression = num * * Set this document's compression mode. */ static VALUE rxml_document_compression_set(VALUE self, VALUE num) { #ifdef HAVE_ZLIB_H xmlDocPtr xdoc; int compmode; Check_Type(num, T_FIXNUM); Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc == NULL) { return(Qnil); } else { xmlSetDocCompressMode(xdoc, NUM2INT(num)); compmode = xmlGetDocCompressMode(xdoc); if (compmode == -1) return(Qnil); else return(INT2NUM(compmode)); } #else rb_warn("libxml compiled without zlib support"); return (Qfalse); #endif } /* * call-seq: * document.compression? -> (true|false) * * Determine whether this document is compressed. */ static VALUE rxml_document_compression_q(VALUE self) { #ifdef HAVE_ZLIB_H xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->compression != -1) return(Qtrue); else return(Qfalse); #else rb_warn("libxml compiled without zlib support"); return (Qfalse); #endif } /* * call-seq: * document.child -> node * * Get this document's child node. */ static VALUE rxml_document_child_get(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->children == NULL) return (Qnil); return rxml_node_wrap(xdoc->children); } /* * call-seq: * document.child? -> (true|false) * * Determine whether this document has a child node. */ static VALUE rxml_document_child_q(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->children == NULL) return (Qfalse); else return (Qtrue); } /* * call-seq: * node.debug -> true|false * * Print libxml debugging information to stdout. * Requires that libxml was compiled with debugging enabled. */ static VALUE rxml_document_debug(VALUE self) { #ifdef LIBXML_DEBUG_ENABLED xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); xmlDebugDumpDocument(NULL, xdoc); return Qtrue; #else rb_warn("libxml was compiled without debugging support."); return Qfalse; #endif } /* * call-seq: * document.encoding -> XML::Encoding::UTF_8 * * Returns the LibXML encoding constant specified by this document. */ static VALUE rxml_document_encoding_get(VALUE self) { xmlDocPtr xdoc; const char *xencoding; Data_Get_Struct(self, xmlDoc, xdoc); xencoding = (const char*)xdoc->encoding; return INT2NUM(xmlParseCharEncoding(xencoding)); } /* * call-seq: * document.rb_encoding -> Encoding * * Returns the Ruby encoding specified by this document * (available on Ruby 1.9.x and higher). */ static VALUE rxml_document_rb_encoding_get(VALUE self) { xmlDocPtr xdoc; rb_encoding* rbencoding; Data_Get_Struct(self, xmlDoc, xdoc); rbencoding = rxml_xml_encoding_to_rb_encoding(mXMLEncoding, xmlParseCharEncoding((const char*)xdoc->encoding)); return rb_enc_from_encoding(rbencoding); } /* * call-seq: * document.encoding = XML::Encoding::UTF_8 * * Set the encoding for this document. */ static VALUE rxml_document_encoding_set(VALUE self, VALUE encoding) { xmlDocPtr xdoc; const char* xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(encoding)); Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->encoding != NULL) xmlFree((xmlChar *) xdoc->encoding); xdoc->encoding = xmlStrdup((xmlChar *)xencoding); return self; } /* * call-seq: * document.import(node) -> XML::Node * * Creates a copy of the node that can be inserted into the * current document. * * IMPORTANT - The returned node MUST be inserted into the document. * This is because the returned node refereces internal LibXML data * structures owned by the document. Therefore, if the document is * is freed before the the node is freed a segmentation fault will occur. */ static VALUE rxml_document_import(VALUE self, VALUE node) { xmlDocPtr xdoc; xmlNodePtr xnode, xresult; Data_Get_Struct(self, xmlDoc, xdoc); Data_Get_Struct(node, xmlNode, xnode); xresult = xmlDocCopyNode(xnode, xdoc, 1); if (xresult == NULL) rxml_raise(xmlGetLastError()); return rxml_node_wrap(xresult); } /* * call-seq: * document.last -> node * * Obtain the last node. */ static VALUE rxml_document_last_get(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->last == NULL) return (Qnil); return rxml_node_wrap(xdoc->last); } /* * call-seq: * document.last? -> (true|false) * * Determine whether there is a last node. */ static VALUE rxml_document_last_q(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->last == NULL) return (Qfalse); else return (Qtrue); } /* * call-seq: * document.next -> node * * Obtain the next node. */ static VALUE rxml_document_next_get(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->next == NULL) return (Qnil); return rxml_node_wrap(xdoc->next); } /* * call-seq: * document.next? -> (true|false) * * Determine whether there is a next node. */ static VALUE rxml_document_next_q(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->next == NULL) return (Qfalse); else return (Qtrue); } /* * call-seq: * node.type -> num * * Obtain this node's type identifier. */ static VALUE rxml_document_node_type(VALUE self) { xmlNodePtr xnode; Data_Get_Struct(self, xmlNode, xnode); return (INT2NUM(xnode->type)); } /* * call-seq: * document.parent -> node * * Obtain the parent node. */ static VALUE rxml_document_parent_get(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->parent == NULL) return (Qnil); return rxml_node_wrap(xdoc->parent); } /* * call-seq: * document.parent? -> (true|false) * * Determine whether there is a parent node. */ static VALUE rxml_document_parent_q(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->parent == NULL) return (Qfalse); else return (Qtrue); } /* * call-seq: * document.prev -> node * * Obtain the previous node. */ static VALUE rxml_document_prev_get(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->prev == NULL) return (Qnil); return rxml_node_wrap(xdoc->prev); } /* * call-seq: * document.prev? -> (true|false) * * Determine whether there is a previous node. */ static VALUE rxml_document_prev_q(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->prev == NULL) return (Qfalse); else return (Qtrue); } /* * call-seq: * document.root -> node * * Obtain the root node. */ static VALUE rxml_document_root_get(VALUE self) { xmlDocPtr xdoc; xmlNodePtr root; Data_Get_Struct(self, xmlDoc, xdoc); root = xmlDocGetRootElement(xdoc); if (root == NULL) return (Qnil); return rxml_node_wrap(root); } /* * call-seq: * document.root = node * * Set the root node. */ static VALUE rxml_document_root_set(VALUE self, VALUE node) { xmlDocPtr xdoc; xmlNodePtr xnode; if (rb_obj_is_kind_of(node, cXMLNode) == Qfalse) rb_raise(rb_eTypeError, "must pass an XML::Node type object"); Data_Get_Struct(self, xmlDoc, xdoc); Data_Get_Struct(node, xmlNode, xnode); if (xnode->doc != NULL && xnode->doc != xdoc) rb_raise(eXMLError, "Nodes belong to different documents. You must first import the node by calling LibXML::XML::Document.import"); xmlDocSetRootElement(xdoc, xnode); // Ruby no longer manages this nodes memory rxml_node_unmanage(xnode, node); return node; } /* * call-seq: * document.save(filename) -> int * document.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8) -> int * * Saves a document to a file. You may provide an optional hash table * to control how the string is generated. Valid options are: * * :indent - Specifies if the string should be indented. The default value * is true. Note that indentation is only added if both :indent is * true and XML.indent_tree_output is true. If :indent is set to false, * then both indentation and line feeds are removed from the result. * * :encoding - Specifies the output encoding of the string. It * defaults to the original encoding of the document (see * #encoding. To override the orginal encoding, use one of the * XML::Encoding encoding constants. */ static VALUE rxml_document_save(int argc, VALUE *argv, VALUE self) { VALUE options = Qnil; VALUE filename = Qnil; xmlDocPtr xdoc; int indent = 1; const char *xfilename; const xmlChar *xencoding; int length; rb_scan_args(argc, argv, "11", &filename, &options); Check_Type(filename, T_STRING); xfilename = StringValuePtr(filename); Data_Get_Struct(self, xmlDoc, xdoc); xencoding = xdoc->encoding; if (!NIL_P(options)) { VALUE rencoding, rindent; Check_Type(options, T_HASH); rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding"))); rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent"))); if (rindent == Qfalse) indent = 0; if (rencoding != Qnil) { xencoding = (const xmlChar*)xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding)); if (!xencoding) rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding)); } } length = xmlSaveFormatFileEnc(xfilename, xdoc, (const char*)xencoding, indent); if (length == -1) rxml_raise(xmlGetLastError()); return (INT2NUM(length)); } /* * call-seq: * document.standalone? -> (true|false) * * Determine whether this is a standalone document. */ static VALUE rxml_document_standalone_q(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->standalone) return (Qtrue); else return (Qfalse); } /* * call-seq: * document.to_s -> "string" * document.to_s(:indent => true, :encoding => XML::Encoding::UTF_8) -> "string" * * Converts a document, and all of its children, to a string representation. * You may provide an optional hash table to control how the string is * generated. Valid options are: * * :indent - Specifies if the string should be indented. The default value * is true. Note that indentation is only added if both :indent is * true and XML.indent_tree_output is true. If :indent is set to false, * then both indentation and line feeds are removed from the result. * * :encoding - Specifies the output encoding of the string. It * defaults to XML::Encoding::UTF8. To change it, use one of the * XML::Encoding encoding constants. */ static VALUE rxml_document_to_s(int argc, VALUE *argv, VALUE self) { VALUE result; VALUE options = Qnil; xmlDocPtr xdoc; int indent = 1; const xmlChar *xencoding = (const xmlChar*) "UTF-8"; xmlChar *buffer; int length; rb_scan_args(argc, argv, "01", &options); if (!NIL_P(options)) { VALUE rencoding, rindent; Check_Type(options, T_HASH); rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding"))); rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent"))); if (rindent == Qfalse) indent = 0; if (rencoding != Qnil) { xencoding = (const xmlChar*)xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding)); if (!xencoding) rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding)); } } Data_Get_Struct(self, xmlDoc, xdoc); xmlDocDumpFormatMemoryEnc(xdoc, &buffer, &length, (const char*)xencoding, indent); result = rxml_new_cstr(buffer, xencoding); xmlFree(buffer); return result; } /* * call-seq: * document.url -> "url" * * Obtain this document's source URL, if any. */ static VALUE rxml_document_url_get(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->URL == NULL) return (Qnil); else return (rxml_new_cstr( xdoc->URL, NULL)); } /* * call-seq: * document.version -> "version" * * Obtain the XML version specified by this document. */ static VALUE rxml_document_version_get(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); if (xdoc->version == NULL) return (Qnil); else return (rxml_new_cstr( xdoc->version, NULL)); } /* * call-seq: * document.xhtml? -> (true|false) * * Determine whether this is an XHTML document. */ static VALUE rxml_document_xhtml_q(VALUE self) { xmlDocPtr xdoc; xmlDtdPtr xdtd; Data_Get_Struct(self, xmlDoc, xdoc); xdtd = xmlGetIntSubset(xdoc); if (xdtd != NULL && xmlIsXHTML(xdtd->SystemID, xdtd->ExternalID) > 0) return (Qtrue); else return (Qfalse); } /* * call-seq: * document.xinclude -> num * * Process xinclude directives in this document. */ static VALUE rxml_document_xinclude(VALUE self) { #ifdef LIBXML_XINCLUDE_ENABLED xmlDocPtr xdoc; int ret; Data_Get_Struct(self, xmlDoc, xdoc); ret = xmlXIncludeProcess(xdoc); if (ret >= 0) { return(INT2NUM(ret)); } else { rxml_raise(xmlGetLastError()); return Qnil; } #else rb_warn( "libxml was compiled without XInclude support. Please recompile libxml and ruby-libxml"); return (Qfalse); #endif } /* * call-seq: * document.order_elements! * * Call this routine to speed up XPath computation on static documents. * This stamps all the element nodes with the document order. */ static VALUE rxml_document_order_elements(VALUE self) { xmlDocPtr xdoc; Data_Get_Struct(self, xmlDoc, xdoc); return LONG2FIX(xmlXPathOrderDocElems(xdoc)); } /* * call-seq: * document.validate_schema(schema) * * Validate this document against the specified XML::Schema. * If the document is valid the method returns true. Otherwise an * exception is raised with validation information. */ static VALUE rxml_document_validate_schema(VALUE self, VALUE schema) { xmlSchemaValidCtxtPtr vptr; xmlDocPtr xdoc; xmlSchemaPtr xschema; int is_invalid; Data_Get_Struct(self, xmlDoc, xdoc); Data_Get_Struct(schema, xmlSchema, xschema); vptr = xmlSchemaNewValidCtxt(xschema); is_invalid = xmlSchemaValidateDoc(vptr, xdoc); xmlSchemaFreeValidCtxt(vptr); if (is_invalid) { rxml_raise(xmlGetLastError()); return Qfalse; } else { return Qtrue; } } /* * call-seq: * document.validate_relaxng(relaxng) * * Validate this document against the specified XML::RelaxNG. * If the document is valid the method returns true. Otherwise an * exception is raised with validation information. */ static VALUE rxml_document_validate_relaxng(VALUE self, VALUE relaxng) { xmlRelaxNGValidCtxtPtr vptr; xmlDocPtr xdoc; xmlRelaxNGPtr xrelaxng; int is_invalid; Data_Get_Struct(self, xmlDoc, xdoc); Data_Get_Struct(relaxng, xmlRelaxNG, xrelaxng); vptr = xmlRelaxNGNewValidCtxt(xrelaxng); is_invalid = xmlRelaxNGValidateDoc(vptr, xdoc); xmlRelaxNGFreeValidCtxt(vptr); if (is_invalid) { rxml_raise(xmlGetLastError()); return Qfalse; } else { return Qtrue; } } /* * call-seq: * document.validate(dtd) -> (true|false) * * Validate this document against the specified XML::DTD. * If the document is valid the method returns true. Otherwise an * exception is raised with validation information. */ static VALUE rxml_document_validate_dtd(VALUE self, VALUE dtd) { xmlValidCtxt ctxt; xmlDocPtr xdoc; xmlDtdPtr xdtd; Data_Get_Struct(self, xmlDoc, xdoc); Data_Get_Struct(dtd, xmlDtd, xdtd); /* Setup context */ memset(&ctxt, 0, sizeof(xmlValidCtxt)); if (xmlValidateDtd(&ctxt, xdoc, xdtd)) { return Qtrue; } else { rxml_raise(xmlGetLastError()); return Qfalse; } } void rxml_init_document(void) { cXMLDocument = rb_define_class_under(mXML, "Document", rb_cObject); rb_define_alloc_func(cXMLDocument, rxml_document_alloc); /* Original C14N 1.0 spec */ rb_define_const(cXMLDocument, "XML_C14N_1_0", INT2NUM(XML_C14N_1_0)); /* Exclusive C14N 1.0 spec */ rb_define_const(cXMLDocument, "XML_C14N_EXCLUSIVE_1_0", INT2NUM(XML_C14N_EXCLUSIVE_1_0)); /* C14N 1.1 spec */ rb_define_const(cXMLDocument, "XML_C14N_1_1", INT2NUM(XML_C14N_1_1)); rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1); rb_define_method(cXMLDocument, "canonicalize", rxml_document_canonicalize, -1); rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0); rb_define_method(cXMLDocument, "child?", rxml_document_child_q, 0); rb_define_method(cXMLDocument, "compression", rxml_document_compression_get, 0); rb_define_method(cXMLDocument, "compression=", rxml_document_compression_set, 1); rb_define_method(cXMLDocument, "compression?", rxml_document_compression_q, 0); rb_define_method(cXMLDocument, "debug", rxml_document_debug, 0); rb_define_method(cXMLDocument, "encoding", rxml_document_encoding_get, 0); rb_define_method(cXMLDocument, "rb_encoding", rxml_document_rb_encoding_get, 0); rb_define_method(cXMLDocument, "encoding=", rxml_document_encoding_set, 1); rb_define_method(cXMLDocument, "import", rxml_document_import, 1); rb_define_method(cXMLDocument, "last", rxml_document_last_get, 0); rb_define_method(cXMLDocument, "last?", rxml_document_last_q, 0); rb_define_method(cXMLDocument, "next", rxml_document_next_get, 0); rb_define_method(cXMLDocument, "next?", rxml_document_next_q, 0); rb_define_method(cXMLDocument, "node_type", rxml_document_node_type, 0); rb_define_method(cXMLDocument, "order_elements!", rxml_document_order_elements, 0); rb_define_method(cXMLDocument, "parent", rxml_document_parent_get, 0); rb_define_method(cXMLDocument, "parent?", rxml_document_parent_q, 0); rb_define_method(cXMLDocument, "prev", rxml_document_prev_get, 0); rb_define_method(cXMLDocument, "prev?", rxml_document_prev_q, 0); rb_define_method(cXMLDocument, "root", rxml_document_root_get, 0); rb_define_method(cXMLDocument, "root=", rxml_document_root_set, 1); rb_define_method(cXMLDocument, "save", rxml_document_save, -1); rb_define_method(cXMLDocument, "standalone?", rxml_document_standalone_q, 0); rb_define_method(cXMLDocument, "to_s", rxml_document_to_s, -1); rb_define_method(cXMLDocument, "url", rxml_document_url_get, 0); rb_define_method(cXMLDocument, "version", rxml_document_version_get, 0); rb_define_method(cXMLDocument, "xhtml?", rxml_document_xhtml_q, 0); rb_define_method(cXMLDocument, "xinclude", rxml_document_xinclude, 0); rb_define_method(cXMLDocument, "validate", rxml_document_validate_dtd, 1); rb_define_method(cXMLDocument, "validate_schema", rxml_document_validate_schema, 1); rb_define_method(cXMLDocument, "validate_relaxng", rxml_document_validate_relaxng, 1); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_writer.c0000644000004100000410000010603114620142101021475 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_writer.h" #ifdef LIBXML_WRITER_ENABLED #include #endif VALUE cXMLWriter; static VALUE sEncoding, sStandalone; #ifdef LIBXML_WRITER_ENABLED /* * Document-class: LibXML::XML::Writer * * The XML::Writer class provides a simpler, alternative way to build a valid * XML document from scratch (forward-only) compared to a DOM approach (based * on XML::Document class). * * For a more in depth tutorial, albeit in C, see http://xmlsoft.org/xmlwriter.html */ #include typedef enum { RXMLW_OUTPUT_NONE, RXMLW_OUTPUT_IO, RXMLW_OUTPUT_DOC, RXMLW_OUTPUT_STRING } rxmlw_output_type; typedef struct { VALUE output; rb_encoding* encoding; xmlBufferPtr buffer; xmlTextWriterPtr writer; rxmlw_output_type output_type; int closed; } rxml_writer_object; static void rxml_writer_free(rxml_writer_object* rwo) { #if 0 /* seems to be done by xmlFreeTextWriter */ if (NULL != rwo->buffer) { xmlBufferFree(rwo->buffer); } #endif rwo->closed = 1; xmlFreeTextWriter(rwo->writer); xfree(rwo); } static void rxml_writer_mark(rxml_writer_object* rwo) { if (!NIL_P(rwo->output)) { rb_gc_mark(rwo->output); } } static VALUE rxml_writer_wrap(rxml_writer_object* rwo) { return Data_Wrap_Struct(cXMLWriter, rxml_writer_mark, rxml_writer_free, rwo); } static rxml_writer_object* rxml_textwriter_get(VALUE obj) { rxml_writer_object* rwo; Data_Get_Struct(obj, rxml_writer_object, rwo); return rwo; } int rxml_writer_write_callback(void* context, const char* buffer, int len) { rxml_writer_object* rwo = context; if (rwo->closed) { return 0; } else { return rxml_write_callback(rwo->output, buffer, len); } } /* ===== public class methods ===== */ /* call-seq: * XML::Writer::io(io) -> XML::Writer * * Creates a XML::Writer which will write XML directly into an IO object. */ static VALUE rxml_writer_io(VALUE klass, VALUE io) { xmlOutputBufferPtr out; rxml_writer_object* rwo; rwo = ALLOC(rxml_writer_object); rwo->output = io; rwo->buffer = NULL; rwo->closed = 0; rwo->encoding = rb_enc_get(io); if (!rwo->encoding) rwo->encoding = rb_utf8_encoding(); rwo->output_type = RXMLW_OUTPUT_IO; xmlCharEncodingHandlerPtr encodingHdlr = xmlFindCharEncodingHandler(rwo->encoding->name); if (NULL == (out = xmlOutputBufferCreateIO(rxml_writer_write_callback, NULL, (void*)rwo, encodingHdlr))) { rxml_raise(xmlGetLastError()); } if (NULL == (rwo->writer = xmlNewTextWriter(out))) { rxml_raise(xmlGetLastError()); } return rxml_writer_wrap(rwo); } /* call-seq: * XML::Writer::file(path) -> XML::Writer * * Creates a XML::Writer object which will write XML into the file with * the given name. */ static VALUE rxml_writer_file(VALUE klass, VALUE filename) { rxml_writer_object* rwo; rwo = ALLOC(rxml_writer_object); rwo->output = Qnil; rwo->buffer = NULL; rwo->closed = 0; rwo->encoding = rb_utf8_encoding(); rwo->output_type = RXMLW_OUTPUT_NONE; if (NULL == (rwo->writer = xmlNewTextWriterFilename(StringValueCStr(filename), 0))) { rxml_raise(xmlGetLastError()); } return rxml_writer_wrap(rwo); } /* call-seq: * XML::Writer::string -> XML::Writer * * Creates a XML::Writer which will write XML into memory, as string. */ static VALUE rxml_writer_string(VALUE klass) { rxml_writer_object* rwo; rwo = ALLOC(rxml_writer_object); rwo->output = Qnil; rwo->closed = 0; rwo->encoding = rb_utf8_encoding(); rwo->output_type = RXMLW_OUTPUT_STRING; if (NULL == (rwo->buffer = xmlBufferCreate())) { rxml_raise(xmlGetLastError()); } if (NULL == (rwo->writer = xmlNewTextWriterMemory(rwo->buffer, 0))) { xmlBufferFree(rwo->buffer); rxml_raise(xmlGetLastError()); } return rxml_writer_wrap(rwo); } /* call-seq: * XML::Writer::document -> XML::Writer * * Creates a XML::Writer which will write into an in memory XML::Document */ static VALUE rxml_writer_doc(VALUE klass) { xmlDocPtr doc; rxml_writer_object* rwo; rwo = ALLOC(rxml_writer_object); rwo->buffer = NULL; rwo->output = Qnil; rwo->closed = 0; rwo->encoding = rb_utf8_encoding(); rwo->output_type = RXMLW_OUTPUT_DOC; if (NULL == (rwo->writer = xmlNewTextWriterDoc(&doc, 0))) { rxml_raise(xmlGetLastError()); } rwo->output = rxml_document_wrap(doc); return rxml_writer_wrap(rwo); } /* ===== public instance methods ===== */ /* call-seq: * writer.flush(empty? = true) -> (num|string) * * Flushes the output buffer. Returns the number of written bytes or * the current content of the internal buffer for a in memory XML::Writer. * If +empty?+ is +true+, and for a in memory XML::Writer, this internel * buffer is empty. */ static VALUE rxml_writer_flush(int argc, VALUE* argv, VALUE self) { int ret; VALUE empty; rxml_writer_object* rwo; rb_scan_args(argc, argv, "01", &empty); rwo = rxml_textwriter_get(self); if (-1 == (ret = xmlTextWriterFlush(rwo->writer))) { rxml_raise(xmlGetLastError()); } if (NULL != rwo->buffer) { VALUE content; content = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding); if (NIL_P(empty) || RTEST(empty)) { /* nil = default value = true */ xmlBufferEmpty(rwo->buffer); } return content; } else { return INT2NUM(ret); } } /* call-seq: * writer.result -> (XML::Document|"string"|nil) * * Returns the associated result object to the XML::Writer creation. * A String for a XML::Writer object created with XML::Writer::string, * a XML::Document with XML::Writer::document, etc. */ static VALUE rxml_writer_result(VALUE self) { VALUE ret = Qnil; rxml_writer_object* rwo = rxml_textwriter_get(self); int bytesWritten = xmlTextWriterFlush(rwo->writer); if (bytesWritten == -1) { rxml_raise(xmlGetLastError()); } switch (rwo->output_type) { case RXMLW_OUTPUT_DOC: ret = rwo->output; break; case RXMLW_OUTPUT_STRING: ret = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding); break; case RXMLW_OUTPUT_IO: case RXMLW_OUTPUT_NONE: break; default: rb_bug("unexpected output"); break; } return ret; } /* ===== private helpers ===== */ static VALUE numeric_rxml_writer_void(VALUE obj, int (*fn)(xmlTextWriterPtr)) { int ret; rxml_writer_object* rwo; rwo = rxml_textwriter_get(obj); ret = fn(rwo->writer); return (-1 == ret ? Qfalse : Qtrue); } #define numeric_rxml_writer_string(/*VALUE*/ obj, /*VALUE*/ name_or_content, /*int (**/fn/*)(xmlTextWriterPtr, const xmlChar *)*/) \ numeric_rxml_writer_va_strings(obj, Qundef, 1, fn, name_or_content) /** * This is quite ugly but thanks to libxml2 coding style, all xmlTextWriter* * calls can be redirected to a single function. This can be convenient to: * - avoid repeating yourself * - convert strings to UTF-8 * - validate names * and so on **/ #define XMLWRITER_MAX_STRING_ARGS 5 static VALUE numeric_rxml_writer_va_strings(VALUE obj, VALUE pe, size_t strings_count, int (*fn)(ANYARGS), ...) { va_list ap; size_t argc; int ret = -1; rxml_writer_object* rwo; const xmlChar* argv[XMLWRITER_MAX_STRING_ARGS]; VALUE utf8[XMLWRITER_MAX_STRING_ARGS], orig[XMLWRITER_MAX_STRING_ARGS]; if (strings_count > XMLWRITER_MAX_STRING_ARGS) { rb_bug("more arguments than expected"); } va_start(ap, fn); rwo = rxml_textwriter_get(obj); for (argc = 0; argc < strings_count; argc++) { VALUE arg; arg = va_arg(ap, VALUE); orig[argc] = arg; if (NIL_P(arg)) { utf8[argc] = Qnil; argv[argc] = NULL; } else { utf8[argc] = rb_str_conv_enc(orig[argc], rb_enc_get(orig[argc]), rwo->encoding); argv[argc] = BAD_CAST StringValueCStr(utf8[argc]); } } va_end(ap); if (Qundef == pe) { switch (strings_count) { case 0: ret = fn(rwo->writer); break; case 1: ret = fn(rwo->writer, argv[0]); break; case 2: ret = fn(rwo->writer, argv[0], argv[1]); break; case 3: ret = fn(rwo->writer, argv[0], argv[1], argv[2]); break; case 4: ret = fn(rwo->writer, argv[0], argv[1], argv[2], argv[3]); break; case 5: ret = fn(rwo->writer, argv[0], argv[1], argv[2], argv[3], argv[4]); break; default: break; } } else { int xpe; xpe = RTEST(pe); switch (strings_count) { /* strings_count doesn't include pe */ case 0: ret = fn(rwo->writer, xpe); break; case 1: ret = fn(rwo->writer, xpe, argv[0]); break; case 2: ret = fn(rwo->writer, xpe, argv[0], argv[1]); break; case 3: ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2]); break; case 4: ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2], argv[3]); break; case 5: ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2], argv[3], argv[4]); break; default: break; } } while (--strings_count > 0) { if (!NIL_P(orig[strings_count])) { if (orig[strings_count] != utf8[strings_count]) { rb_str_free(utf8[strings_count]); } } } return (-1 == ret ? Qfalse : Qtrue); } /* ===== public instance methods ===== */ #if LIBXML_VERSION >= 20605 /* call-seq: * writer.set_indent(indentation) -> (true|false) * * Toggles indentation on or off. Returns +false+ on failure. * * Availability: libxml2 >= 2.6.5 */ static VALUE rxml_writer_set_indent(VALUE self, VALUE indentation) { int ret; rxml_writer_object* rwo; rwo = rxml_textwriter_get(self); ret = xmlTextWriterSetIndent(rwo->writer, RTEST(indentation)); return (-1 == ret ? Qfalse : Qtrue); } /* call-seq: * writer.set_indent_string(string) -> (true|false) * * Sets the string to use to indent each element of the document. * Don't forget to enable indentation with set_indent. Returns * +false+ on failure. * * Availability: libxml2 >= 2.6.5 */ static VALUE rxml_writer_set_indent_string(VALUE self, VALUE indentation) { return numeric_rxml_writer_string(self, indentation, xmlTextWriterSetIndentString); } #endif /* LIBXML_VERSION >= 20605 */ /* ===== public full tag interface ===== */ /* write_ = start_ + write_string + end_ */ /* call-seq: * writer.write_comment(content) -> (true|false) * * Writes a full comment tag, all at once. Returns +false+ on failure. * This is equivalent to start_comment + write_string(content) + end_comment. */ static VALUE rxml_writer_write_comment(VALUE self, VALUE content) { return numeric_rxml_writer_string(self, content, xmlTextWriterWriteComment); } /* call-seq: * writer.write_cdata(content) -> (true|false) * * Writes a full CDATA section, all at once. Returns +false+ on failure. * This is equivalent to start_cdata + write_string(content) + end_cdata. */ static VALUE rxml_writer_write_cdata(VALUE self, VALUE content) { return numeric_rxml_writer_string(self, content, xmlTextWriterWriteCDATA); } static VALUE rxml_writer_start_element(VALUE, VALUE); static VALUE rxml_writer_start_element_ns(int, VALUE*, VALUE); static VALUE rxml_writer_end_element(VALUE); /* call-seq: * writer.write_element(name, content) -> (true|false) * * Writes a full element tag, all at once. Returns +false+ on failure. * This is equivalent to start_element(name) + write_string(content) + * end_element. */ static VALUE rxml_writer_write_element(int argc, VALUE* argv, VALUE self) { VALUE name, content; rb_scan_args(argc, argv, "11", &name, &content); if (Qnil == content) { if (Qfalse == rxml_writer_start_element(self, name)) { return Qfalse; } return rxml_writer_end_element(self); } else { return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteElement, name, content); } } #define ARRAY_SIZE(array) \ (sizeof(array) / sizeof((array)[0])) /* call-seq: * writer.write_element_ns(prefix, name, namespaceURI, content) -> (true|false) * * Writes a full namespaced element tag, all at once. Returns +false+ on failure. * This is a shortcut for start_element_ns(prefix, name, namespaceURI) + * write_string(content) + end_element. * * Notes: * - by default, the xmlns: definition is repeated on every element. If you want * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+ * to nil or omit it. Don't forget to declare the namespace prefix somewhere * earlier. * - +content+ can be omitted for an empty tag */ static VALUE rxml_writer_write_element_ns(int argc, VALUE* argv, VALUE self) { VALUE prefix, name, namespaceURI, content; rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content); if (Qnil == content) { VALUE argv[3] = { prefix, name, namespaceURI }; if (Qfalse == rxml_writer_start_element_ns(ARRAY_SIZE(argv), argv, self)) { return Qfalse; } return rxml_writer_end_element(self); } else { return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteElementNS, prefix, name, namespaceURI, content); } } /* call-seq: * writer.write_attribute(name, content) -> (true|false) * * Writes a full attribute, all at once. Returns +false+ on failure. * Same as start_attribute(name) + write_string(content) + end_attribute. */ static VALUE rxml_writer_write_attribute(VALUE self, VALUE name, VALUE content) { return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteAttribute, name, content); } /* call-seq: * writer.write_attribute_ns(prefix, name, namespaceURI, content) -> (true|false) * * Writes a full namespaced attribute, all at once. Returns +false+ on failure. * Same as start_attribute_ns(prefix, name, namespaceURI) + * write_string(content) + end_attribute. * * Notes: * - by default, the xmlns: definition is repeated on every element. If you want * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+ * to nil or omit it. Don't forget to declare the namespace prefix somewhere * earlier. * - +content+ can be omitted too for an empty attribute */ static VALUE rxml_writer_write_attribute_ns(int argc, VALUE* argv, VALUE self) { VALUE prefix, name, namespaceURI, content; rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content); return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteAttributeNS, prefix, name, namespaceURI, content); } /* call-seq: * writer.write_pi(target, content) -> (true|false) * * Writes a full CDATA tag, all at once. Returns +false+ on failure. * This is a shortcut for start_pi(target) + write_string(content) + end_pi. */ static VALUE rxml_writer_write_pi(VALUE self, VALUE target, VALUE content) { return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWritePI, target, content); } /* ===== public start/end interface ===== */ /* call-seq: * writer.write_string(content) -> (true|false) * * Safely (problematic characters are internally translated to their * associated named entities) writes a string into the current node * (attribute, element, comment, ...). Returns +false+ on failure. */ static VALUE rxml_writer_write_string(VALUE self, VALUE content) { return numeric_rxml_writer_string(self, content, xmlTextWriterWriteString); } /* call-seq: * writer.write_raw(content) -> (true|false) * * Writes the string +content+ as is, reserved characters are not * translated to their associated entities. Returns +false+ on failure. * Consider write_string to handle them. */ static VALUE rxml_writer_write_raw(VALUE self, VALUE content) { return numeric_rxml_writer_string(self, content, xmlTextWriterWriteRaw); } /* call-seq: * writer.start_attribute(name) -> (true|false) * * Starts an attribute. Returns +false+ on failure. */ static VALUE rxml_writer_start_attribute(VALUE self, VALUE name) { return numeric_rxml_writer_string(self, name, xmlTextWriterStartAttribute); } /* call-seq: * writer.start_attribute_ns(prefix, name, namespaceURI) -> (true|false) * * Starts a namespaced attribute. Returns +false+ on failure. * * Note: by default, the xmlns: definition is repeated on every element. If * you want the prefix, but don't want the xmlns: declaration repeated, set * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace * prefix somewhere earlier. */ static VALUE rxml_writer_start_attribute_ns(int argc, VALUE* argv, VALUE self) { VALUE prefix, name, namespaceURI; rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI); return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartAttributeNS, prefix, name, namespaceURI); } /* call-seq: * writer.end_attribute -> (true|false) * * Ends an attribute, namespaced or not. Returns +false+ on failure. */ static VALUE rxml_writer_end_attribute(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndAttribute); } #if LIBXML_VERSION >= 20607 /* call-seq: * writer.start_comment -> (true|false) * * Starts a comment. Returns +false+ on failure. * Note: libxml2 >= 2.6.7 required */ static VALUE rxml_writer_start_comment(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterStartComment); } /* call-seq: * writer.end_comment -> (true|false) * * Ends current comment, returns +false+ on failure. * Note: libxml2 >= 2.6.7 required */ static VALUE rxml_writer_end_comment(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndComment); } #endif /* LIBXML_VERSION >= 20607 */ /* call-seq: * writer.start_element(name) -> (true|false) * * Starts a new element. Returns +false+ on failure. */ static VALUE rxml_writer_start_element(VALUE self, VALUE name) { return numeric_rxml_writer_string(self, name, xmlTextWriterStartElement); } /* call-seq: * writer.start_element_ns(prefix, name, namespaceURI) -> (true|false) * * Starts a new namespaced element. Returns +false+ on failure. * * Note: by default, the xmlns: definition is repeated on every element. If * you want the prefix, but don't want the xmlns: declaration repeated, set * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace * prefix somewhere earlier. */ static VALUE rxml_writer_start_element_ns(int argc, VALUE* argv, VALUE self) { VALUE prefix, name, namespaceURI; rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI); return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartElementNS, prefix, name, namespaceURI); } /* call-seq: * writer.end_element -> (true|false) * * Ends current element, namespaced or not. Returns +false+ on failure. */ static VALUE rxml_writer_end_element(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndElement); } /* call-seq: * writer.write_full_end_element -> (true|false) * * Ends current element, namespaced or not. Returns +false+ on failure. * This method writes an end tag even if the element is empty (), * end_element does not (). */ static VALUE rxml_writer_full_end_element(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterFullEndElement); } /* call-seq: * writer.start_cdata -> (true|false) * * Starts a new CDATA section. Returns +false+ on failure. */ static VALUE rxml_writer_start_cdata(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterStartCDATA); } /* call-seq: * writer.end_cdata -> (true|false) * * Ends current CDATA section. Returns +false+ on failure. */ static VALUE rxml_writer_end_cdata(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndCDATA); } /* call-seq: * writer.start_document -> (true|false) * writer.start_document(:encoding => XML::Encoding::UTF_8, * :standalone => true) -> (true|false) * * Starts a new document. Returns +false+ on failure. * * You may provide an optional hash table to control XML header that will be * generated. Valid options are: * - encoding: the output document encoding, defaults to nil (= UTF-8). Valid * values are the encoding constants defined on XML::Encoding * - standalone: nil (default) or a boolean to indicate if the document is * standalone or not */ static VALUE rxml_writer_start_document(int argc, VALUE* argv, VALUE self) { int ret; VALUE options = Qnil; rxml_writer_object* rwo; const xmlChar* xencoding = NULL; const char* xstandalone = NULL; rb_scan_args(argc, argv, "01", &options); if (!NIL_P(options)) { VALUE encoding, standalone; encoding = standalone = Qnil; Check_Type(options, T_HASH); encoding = rb_hash_aref(options, sEncoding); xencoding = NIL_P(encoding) ? NULL : (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding)); standalone = rb_hash_aref(options, sStandalone); if (NIL_P(standalone)) { xstandalone = NULL; } else { xstandalone = RTEST(standalone) ? "yes" : "no"; } } rwo = rxml_textwriter_get(self); rwo->encoding = rxml_figure_encoding(xencoding); ret = xmlTextWriterStartDocument(rwo->writer, NULL, (const char*)xencoding, xstandalone); return (-1 == ret ? Qfalse : Qtrue); } /* call-seq: * writer.end_document -> (true|false) * * Ends current document. Returns +false+ on failure. */ static VALUE rxml_writer_end_document(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndDocument); } /* call-seq: * writer.start_pi(target) -> (true|false) * * Starts a new processing instruction. Returns +false+ on failure. */ static VALUE rxml_writer_start_pi(VALUE self, VALUE target) { return numeric_rxml_writer_string(self, target, xmlTextWriterStartPI); } /* call-seq: * writer.end_pi -> (true|false) * * Ends current processing instruction. Returns +false+ on failure. */ static VALUE rxml_writer_end_pi(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndPI); } /* call-seq: * writer.start_dtd(qualifiedName, publicId, systemId) -> (true|false) * * Starts a DTD. Returns +false+ on failure. */ static VALUE rxml_writer_start_dtd(int argc, VALUE* argv, VALUE self) { VALUE name, pubid, sysid; rb_scan_args(argc, argv, "12", &name, &pubid, &sysid); return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartDTD, name, pubid, sysid); } /* call-seq: * writer.start_dtd_element(qualifiedName) -> (true|false) * * Starts a DTD element (). Returns +false+ on failure. */ static VALUE rxml_writer_start_dtd_element(VALUE self, VALUE name) { return numeric_rxml_writer_string(self, name, xmlTextWriterStartDTDElement); } /* call-seq: * writer.start_dtd_entity(name, pe = false) -> (true|false) * * Starts a DTD entity (). Returns +false+ on failure. */ static VALUE rxml_writer_start_dtd_entity(int argc, VALUE* argv, VALUE self) { VALUE name, pe; rb_scan_args(argc, argv, "11", &name, &pe); if (NIL_P(pe)) { pe = Qfalse; } return numeric_rxml_writer_va_strings(self, pe, 1, xmlTextWriterStartDTDEntity, name); } /* call-seq: * writer.start_dtd_attlist(name) -> (true|false) * * Starts a DTD attribute list (). Returns +false+ on failure. */ static VALUE rxml_writer_start_dtd_attlist(VALUE self, VALUE name) { return numeric_rxml_writer_string(self, name, xmlTextWriterStartDTDAttlist); } /* call-seq: * writer.end_dtd -> (true|false) * * Ends current DTD, returns +false+ on failure. */ static VALUE rxml_writer_end_dtd(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndDTD); } /* call-seq: * writer.end_dtd_entity -> (true|false) * * Ends current DTD entity, returns +false+ on failure. */ static VALUE rxml_writer_end_dtd_entity(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndDTDEntity); } /* call-seq: * writer.end_dtd_attlist -> (true|false) * * Ends current DTD attribute list, returns +false+ on failure. */ static VALUE rxml_writer_end_dtd_attlist(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndDTDAttlist); } /* call-seq: * writer.end_dtd_element -> (true|false) * * Ends current DTD element, returns +false+ on failure. */ static VALUE rxml_writer_end_dtd_element(VALUE self) { return numeric_rxml_writer_void(self, xmlTextWriterEndDTDElement); } /* call-seq: * writer.write_dtd(name [ [ [, publicId ], systemId ], subset ]) -> (true|false) * * Writes a DTD, all at once. Returns +false+ on failure. * - name: dtd name * - publicId: external subset public identifier, use nil for a SYSTEM doctype * - systemId: external subset system identifier * - subset: content * * Examples: * writer.write_dtd 'html' * #=> * writer.write_dtd 'docbook', nil, 'http://www.docbook.org/xml/5.0/dtd/docbook.dtd' * #=> * writer.write_dtd 'html', '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd' * #=> * writer.write_dtd 'person', nil, nil, '' * #=> ]> */ static VALUE rxml_writer_write_dtd(int argc, VALUE* argv, VALUE self) { VALUE name, pubid, sysid, subset; rb_scan_args(argc, argv, "13", &name, &pubid, &sysid, &subset); return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteDTD, name, pubid, sysid, subset); } /* call-seq: * writer.write_dtd_attlist(name, content) -> (true|false) * * Writes a DTD attribute list, all at once. Returns +false+ on failure. * writer.write_dtd_attlist 'id', 'ID #IMPLIED' * #=> */ static VALUE rxml_writer_write_dtd_attlist(VALUE self, VALUE name, VALUE content) { return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteDTDAttlist, name, content); } /* call-seq: * writer.write_dtd_element(name, content) -> (true|false) * * Writes a full DTD element, all at once. Returns +false+ on failure. * writer.write_dtd_element 'person', '(firstname,lastname)' * #=> */ static VALUE rxml_writer_write_dtd_element(VALUE self, VALUE name, VALUE content) { return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteDTDElement, name, content); } /* call-seq: * writer.write_dtd_entity(name, publicId, systemId, ndataid, content, pe) -> (true|false) * * Writes a DTD entity, all at once. Returns +false+ on failure. */ static VALUE rxml_writer_write_dtd_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE content, VALUE pe) { return numeric_rxml_writer_va_strings(self, pe, 5, xmlTextWriterWriteDTDEntity, name, pubid, sysid, ndataid, content); } /* call-seq: * writer.write_dtd_external_entity(name, publicId, systemId, ndataid, pe) -> (true|false) * * Writes a DTD external entity. The entity must have been started * with start_dtd_entity. Returns +false+ on failure. * - name: the name of the DTD entity * - publicId: the public identifier, which is an alternative to the system identifier * - systemId: the system identifier, which is the URI of the DTD * - ndataid: the xml notation name * - pe: +true+ if this is a parameter entity (to be used only in the DTD * itself), +false+ if not */ static VALUE rxml_writer_write_dtd_external_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE pe) { return numeric_rxml_writer_va_strings(self, pe, 4, xmlTextWriterWriteDTDExternalEntity, name, pubid, sysid, ndataid); } /* call-seq: * writer.write_dtd_external_entity_contents(publicId, systemId, ndataid) -> (true|false) * * Writes the contents of a DTD external entity, all at once. Returns +false+ on failure. */ static VALUE rxml_writer_write_dtd_external_entity_contents(VALUE self, VALUE pubid, VALUE sysid, VALUE ndataid) { return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterWriteDTDExternalEntityContents, pubid, sysid, ndataid); } /* call-seq: * writer.write_dtd_internal_entity(name, content, pe) -> (true|false) * * Writes a DTD internal entity, all at once. Returns +false+ on failure. * * Examples: * writer.write_dtd_entity 'Shape', '(rect|circle|poly|default)', true * #=> * writer.write_dtd_entity 'delta', 'δ', false * #=> */ static VALUE rxml_writer_write_dtd_internal_entity(VALUE self, VALUE name, VALUE content, VALUE pe) { return numeric_rxml_writer_va_strings(self, pe, 2, xmlTextWriterWriteDTDInternalEntity, name, content); } /* call-seq: * writer.write_dtd_notation(name, publicId, systemId) -> (true|false) * * Writes a DTD entity, all at once. Returns +false+ on failure. */ static VALUE rxml_writer_write_dtd_notation(VALUE self, VALUE name, VALUE pubid, VALUE sysid) { return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterWriteDTDNotation, name, pubid, sysid); } #if LIBXML_VERSION >= 20900 /* call-seq: * writer.set_quote_char(...) -> (true|false) * * Sets the character used to quote attributes. Returns +false+ on failure. * * Notes: * - only " (default) and ' characters are valid * - availability: libxml2 >= 2.9.0 */ static VALUE rxml_writer_set_quote_char(VALUE self, VALUE quotechar) { int ret; const char* xquotechar; rxml_writer_object* rwo; rwo = rxml_textwriter_get(self); xquotechar = StringValueCStr(quotechar); ret = xmlTextWriterSetQuoteChar(rwo->writer, (xmlChar)xquotechar[0]); return (-1 == ret ? Qfalse : Qtrue); } #endif /* LIBXML_VERSION >= 20900 */ #endif /* LIBXML_WRITER_ENABLED */ /* grep -P 'xmlTextWriter(Start|End|Write)(?!DTD|V?Format)[^(]+' /usr/include/libxml2/libxml/xmlwriter.h */ void rxml_init_writer(void) { sEncoding = ID2SYM(rb_intern("encoding")); sStandalone = ID2SYM(rb_intern("standalone")); cXMLWriter = rb_define_class_under(mXML, "Writer", rb_cObject); rb_undef_alloc_func(cXMLWriter); #ifdef LIBXML_WRITER_ENABLED rb_define_singleton_method(cXMLWriter, "io", rxml_writer_io, 1); rb_define_singleton_method(cXMLWriter, "file", rxml_writer_file, 1); rb_define_singleton_method(cXMLWriter, "document", rxml_writer_doc, 0); rb_define_singleton_method(cXMLWriter, "string", rxml_writer_string, 0); /* misc */ #if LIBXML_VERSION >= 20605 rb_define_method(cXMLWriter, "set_indent", rxml_writer_set_indent, 1); rb_define_method(cXMLWriter, "set_indent_string", rxml_writer_set_indent_string, 1); #endif /* LIBXML_VERSION >= 20605 */ #if LIBXML_VERSION >= 20900 rb_define_method(cXMLWriter, "set_quote_char", rxml_writer_set_quote_char, 1); #endif /* LIBXML_VERSION >= 20900 */ rb_define_method(cXMLWriter, "flush", rxml_writer_flush, -1); rb_define_method(cXMLWriter, "start_dtd", rxml_writer_start_dtd, -1); rb_define_method(cXMLWriter, "start_dtd_entity", rxml_writer_start_dtd_entity, -1); rb_define_method(cXMLWriter, "start_dtd_attlist", rxml_writer_start_dtd_attlist, 1); rb_define_method(cXMLWriter, "start_dtd_element", rxml_writer_start_dtd_element, 1); rb_define_method(cXMLWriter, "write_dtd", rxml_writer_write_dtd, -1); rb_define_method(cXMLWriter, "write_dtd_attlist", rxml_writer_write_dtd_attlist, 2); rb_define_method(cXMLWriter, "write_dtd_element", rxml_writer_write_dtd_element, 2); rb_define_method(cXMLWriter, "write_dtd_entity", rxml_writer_write_dtd_entity, 6); rb_define_method(cXMLWriter, "write_dtd_external_entity", rxml_writer_write_dtd_external_entity, 5); rb_define_method(cXMLWriter, "write_dtd_external_entity_contents", rxml_writer_write_dtd_external_entity_contents, 3); rb_define_method(cXMLWriter, "write_dtd_internal_entity", rxml_writer_write_dtd_internal_entity, 3); rb_define_method(cXMLWriter, "write_dtd_notation", rxml_writer_write_dtd_notation, 3); rb_define_method(cXMLWriter, "end_dtd", rxml_writer_end_dtd, 0); rb_define_method(cXMLWriter, "end_dtd_entity", rxml_writer_end_dtd_entity, 0); rb_define_method(cXMLWriter, "end_dtd_attlist", rxml_writer_end_dtd_attlist, 0); rb_define_method(cXMLWriter, "end_dtd_element", rxml_writer_end_dtd_element, 0); /* tag by parts */ rb_define_method(cXMLWriter, "write_raw", rxml_writer_write_raw, 1); rb_define_method(cXMLWriter, "write_string", rxml_writer_write_string, 1); rb_define_method(cXMLWriter, "start_cdata", rxml_writer_start_cdata, 0); rb_define_method(cXMLWriter, "end_cdata", rxml_writer_end_cdata, 0); rb_define_method(cXMLWriter, "start_attribute", rxml_writer_start_attribute, 1); rb_define_method(cXMLWriter, "start_attribute_ns", rxml_writer_start_attribute_ns, -1); rb_define_method(cXMLWriter, "end_attribute", rxml_writer_end_attribute, 0); rb_define_method(cXMLWriter, "start_element", rxml_writer_start_element, 1); rb_define_method(cXMLWriter, "start_element_ns", rxml_writer_start_element_ns, -1); rb_define_method(cXMLWriter, "end_element", rxml_writer_end_element, 0); rb_define_method(cXMLWriter, "full_end_element", rxml_writer_full_end_element, 0); rb_define_method(cXMLWriter, "start_document", rxml_writer_start_document, -1); rb_define_method(cXMLWriter, "end_document", rxml_writer_end_document, 0); #if LIBXML_VERSION >= 20607 rb_define_method(cXMLWriter, "start_comment", rxml_writer_start_comment, 0); rb_define_method(cXMLWriter, "end_comment", rxml_writer_end_comment, 0); #endif /* LIBXML_VERSION >= 20607 */ rb_define_method(cXMLWriter, "start_pi", rxml_writer_start_pi, 1); rb_define_method(cXMLWriter, "end_pi", rxml_writer_end_pi, 0); /* full tag at once */ rb_define_method(cXMLWriter, "write_attribute", rxml_writer_write_attribute, 2); rb_define_method(cXMLWriter, "write_attribute_ns", rxml_writer_write_attribute_ns, -1); rb_define_method(cXMLWriter, "write_comment", rxml_writer_write_comment, 1); rb_define_method(cXMLWriter, "write_cdata", rxml_writer_write_cdata, 1); rb_define_method(cXMLWriter, "write_element", rxml_writer_write_element, -1); rb_define_method(cXMLWriter, "write_element_ns", rxml_writer_write_element_ns, -1); rb_define_method(cXMLWriter, "write_pi", rxml_writer_write_pi, 2); rb_define_method(cXMLWriter, "result", rxml_writer_result, 0); rb_undef_method(CLASS_OF(cXMLWriter), "new"); #endif } libxml-ruby-5.0.3/ext/libxml/ruby_xml_attr.c0000644000004100000410000001776514620142101021152 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ /* * Document-class: LibXML::XML::Attr * * Provides access to an attribute defined on an element. * * Basic Usage: * * require 'test_helper' * * doc = XML::Document.new() * attribute = doc.root.attributes.get_attribute_ns('http://www.w3.org/1999/xlink', 'href') * attribute.name == 'href' * attribute.value == 'http://www.mydocument.com' * attribute.remove! */ /* Attributes are owned and freed by their nodes. Thus, its easier for the ruby bindings to not manage attribute memory management. This does mean that accessing a particular attribute multiple times will return multiple different ruby objects. Since we are not using free this works out fine. Previous versions of the bindings had a one to one mapping between ruby object and xml attribute, but that could result in segfaults because the ruby object could be gc'ed. In theory the mark method on the parent node could prevent that, but if an attribute is returned using an xpath statement then the node would never by surfaced to ruby and the mark method never called. */ #include "ruby_libxml.h" #include "ruby_xml_attr.h" VALUE cXMLAttr; void rxml_attr_mark(xmlAttrPtr xattr) { /* This can happen if Ruby does a GC run after creating the new attribute but before initializing it. */ if (xattr != NULL) rxml_node_mark((xmlNodePtr) xattr); } VALUE rxml_attr_wrap(xmlAttrPtr xattr) { return Data_Wrap_Struct(cXMLAttr, rxml_attr_mark, NULL, xattr); } static VALUE rxml_attr_alloc(VALUE klass) { return Data_Wrap_Struct(klass, rxml_attr_mark, NULL, NULL); } /* * call-seq: * attr.initialize(node, "name", "value") * * Creates a new attribute for the node. * * node: The XML::Node that will contain the attribute * name: The name of the attribute * value: The value of the attribute * * attr = XML::Attr.new(doc.root, 'name', 'libxml') */ static VALUE rxml_attr_initialize(int argc, VALUE *argv, VALUE self) { VALUE node = argv[0]; VALUE name = argv[1]; VALUE value = argv[2]; VALUE ns = (argc == 4 ? argv[3] : Qnil); xmlNodePtr xnode; xmlAttrPtr xattr; if (argc < 3 || argc > 4) rb_raise(rb_eArgError, "Wrong number of arguments (3 or 4)"); Check_Type(name, T_STRING); Check_Type(value, T_STRING); Data_Get_Struct(node, xmlNode, xnode); if (xnode->type != XML_ELEMENT_NODE) rb_raise(rb_eArgError, "Attributes can only be created on element nodes."); if (NIL_P(ns)) { xattr = xmlNewProp(xnode, (xmlChar*)StringValuePtr(name), (xmlChar*)StringValuePtr(value)); } else { xmlNsPtr xns; Data_Get_Struct(ns, xmlNs, xns); xattr = xmlNewNsProp(xnode, xns, (xmlChar*)StringValuePtr(name), (xmlChar*)StringValuePtr(value)); } if (!xattr) rb_raise(rb_eRuntimeError, "Could not create attribute."); DATA_PTR( self) = xattr; return self; } /* * call-seq: * attr.child -> node * * Obtain this attribute's child attribute(s). */ static VALUE rxml_attr_child_get(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); if (xattr->children == NULL) return Qnil; else return rxml_node_wrap((xmlNodePtr) xattr->children); } /* * call-seq: * attr.doc -> XML::Document * * Returns this attribute's document. * * doc.root.attributes.get_attribute('name').doc == doc */ static VALUE rxml_attr_doc_get(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); if (xattr->doc == NULL) return Qnil; else return rxml_document_wrap(xattr->doc); } /* * call-seq: * attr.last -> node * * Obtain the last attribute. */ static VALUE rxml_attr_last_get(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); if (xattr->last == NULL) return Qnil; else return rxml_node_wrap(xattr->last); } /* * call-seq: * attr.name -> "name" * * Obtain this attribute's name. */ static VALUE rxml_attr_name_get(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); if (xattr->name == NULL) return Qnil; else return rxml_new_cstr( xattr->name, NULL); } /* * call-seq: * attr.next -> node * * Obtain the next attribute. */ static VALUE rxml_attr_next_get(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); if (xattr->next == NULL) return Qnil; else return rxml_attr_wrap(xattr->next); } /* * call-seq: * attr.node_type -> num * * Obtain this node's type identifier. */ static VALUE rxml_attr_node_type(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); return INT2NUM(xattr->type); } /* * call-seq: * attr.ns -> namespace * * Obtain this attribute's associated XML::NS, if any. */ static VALUE rxml_attr_ns_get(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); if (xattr->ns == NULL) return Qnil; else return rxml_namespace_wrap(xattr->ns); } /* * call-seq: * attr.parent -> node * * Obtain this attribute node's parent. */ static VALUE rxml_attr_parent_get(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); if (xattr->parent == NULL) return Qnil; else return rxml_node_wrap(xattr->parent); } /* * call-seq: * attr.prev -> node * * Obtain the previous attribute. */ static VALUE rxml_attr_prev_get(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); if (xattr->prev == NULL) return Qnil; else return rxml_attr_wrap(xattr->prev); } /* * call-seq: * attr.remove! -> nil * * Removes this attribute from it's parent. Note * the attribute and its content is freed and can * no longer be used. If you try to use it you * will get a segmentation fault. */ static VALUE rxml_attr_remove_ex(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); xmlRemoveProp(xattr); RDATA(self)->data = NULL; RDATA(self)->dfree = NULL; RDATA(self)->dmark = NULL; return Qnil; } /* * call-seq: * attr.value -> "value" * * Obtain the value of this attribute. */ VALUE rxml_attr_value_get(VALUE self) { xmlAttrPtr xattr; xmlChar *value; VALUE result = Qnil; Data_Get_Struct(self, xmlAttr, xattr); value = xmlNodeGetContent((xmlNodePtr)xattr); if (value != NULL) { result = rxml_new_cstr( value, NULL); xmlFree(value); } return result; } /* * call-seq: * attr.value = "value" * * Sets the value of this attribute. */ VALUE rxml_attr_value_set(VALUE self, VALUE val) { xmlAttrPtr xattr; Check_Type(val, T_STRING); Data_Get_Struct(self, xmlAttr, xattr); if (xattr->ns) xmlSetNsProp(xattr->parent, xattr->ns, xattr->name, (xmlChar*) StringValuePtr(val)); else xmlSetProp(xattr->parent, xattr->name, (xmlChar*) StringValuePtr(val)); return (self); } void rxml_init_attr(void) { cXMLAttr = rb_define_class_under(mXML, "Attr", rb_cObject); rb_define_alloc_func(cXMLAttr, rxml_attr_alloc); rb_define_method(cXMLAttr, "initialize", rxml_attr_initialize, -1); rb_define_method(cXMLAttr, "child", rxml_attr_child_get, 0); rb_define_method(cXMLAttr, "doc", rxml_attr_doc_get, 0); rb_define_method(cXMLAttr, "last", rxml_attr_last_get, 0); rb_define_method(cXMLAttr, "name", rxml_attr_name_get, 0); rb_define_method(cXMLAttr, "next", rxml_attr_next_get, 0); rb_define_method(cXMLAttr, "node_type", rxml_attr_node_type, 0); rb_define_method(cXMLAttr, "ns", rxml_attr_ns_get, 0); rb_define_method(cXMLAttr, "parent", rxml_attr_parent_get, 0); rb_define_method(cXMLAttr, "prev", rxml_attr_prev_get, 0); rb_define_method(cXMLAttr, "remove!", rxml_attr_remove_ex, 0); rb_define_method(cXMLAttr, "value", rxml_attr_value_get, 0); rb_define_method(cXMLAttr, "value=", rxml_attr_value_set, 1); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_sax2_handler.h0000644000004100000410000000035014620142101022535 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_SAX2_HANDLER__ #define __RXML_SAX2_HANDLER__ extern xmlSAXHandler rxml_sax_handler; void rxml_init_sax2_handler(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema_element.h0000644000004100000410000000036614620142101023143 0ustar www-datawww-data#ifndef __RXML_SCHEMA_ELEMENT__ #define __RXML_SCHEMA_ELEMENT__ #include "ruby_xml_schema.h" extern VALUE cXMLSchemaElement; VALUE rxml_wrap_schema_element(xmlSchemaElementPtr xelement); void rxml_init_schema_element(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_parser_options.h0000644000004100000410000000034714620142101023240 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_PARSER_OPTIONS__ #define __RXML_PARSER_OPTIONS__ extern VALUE mXMLParserOptions; void rxml_init_parser_options(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml.h0000644000004100000410000000026214620142101020105 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RUBY_XML_H__ #define __RUBY_XML_H__ extern VALUE mXML; void rxml_init_xml(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_attributes.h0000644000004100000410000000066514620142101022362 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_ATTRIBUTES__ #define __RXML_ATTRIBUTES__ #include extern VALUE cXMLAttributesibutes; void rxml_init_attributes(void); VALUE rxml_attributes_new(xmlNodePtr xnode); VALUE rxml_attributes_attribute_get(VALUE self, VALUE name); VALUE rxml_attributes_attribute_set(VALUE self, VALUE name, VALUE value); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_namespaces.c0000644000004100000410000002012014620142101022272 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_namespaces.h" VALUE cXMLNamespaces; /* Document-class: LibXML::XML::Namespaces * * The XML::Namespaces class is used to access information about * a node's namespaces. For each node, libxml maintains: * * * The node's namespace (#namespace) * * Which namespaces are defined on the node (#definnitions) * * Which namespaces are in scope for the node (#each) * * Let's look at an example: * * * * * * * * The Envelope node is in the soap namespace. It contains * two namespace definitions, one for soap and one for xsd. * * The Body node is also in the soap namespace and does not * contain any namespaces. However, the soap and xsd namespaces * are both in context. * * The order node is in its default namespace and contains * one namespace definition (http://mynamespace.com). There * are three namespaces in context soap, xsd and the * default namespace. */ static VALUE rxml_namespaces_alloc(VALUE klass) { return Data_Wrap_Struct(klass, NULL, NULL, NULL); } /* * call-seq: * initialize(XML::Node) -> XML::Namespaces * * Creates a new namespaces object. Generally you * do not call this method directly, but instead * access a namespaces object via XML::Node#namespaces. * * Usage: * * doc = XML::Document.string('') * namespaces = new XML::Namespaces(doc.root) */ static VALUE rxml_namespaces_initialize(VALUE self, VALUE node) { xmlNodePtr xnode; Check_Type(node, T_DATA); Data_Get_Struct(node, xmlNode, xnode); DATA_PTR(self) = xnode; return self; } /* * call-seq: * namespaces.definitions -> [XML::Namespace, XML::Namespace] * * Returns an array of XML::Namespace objects that are * defined on this node. * * Usage: * * doc = XML::Document.string('') * defs = doc.root.namespaces.definitions */ static VALUE rxml_namespaces_definitions(VALUE self) { xmlNodePtr xnode; xmlNsPtr xns; VALUE arr; Data_Get_Struct(self, xmlNode, xnode); arr = rb_ary_new(); xns = xnode->nsDef; while (xns) { VALUE anamespace = rxml_namespace_wrap(xns); rb_ary_push(arr, anamespace); xns = xns->next; } return arr; } /* * call-seq: * namespaces.each {|XML::Namespace|} * * Iterates over the namespace objects that are * in context for this node. * * Usage: * * doc = XML::Document.string('') * doc.root.namespaces.each do |ns| * .. * end */ static VALUE rxml_namespaces_each(VALUE self) { xmlNodePtr xnode; xmlNsPtr *nsList, *xns; Data_Get_Struct(self, xmlNode, xnode); nsList = xmlGetNsList(xnode->doc, xnode); if (nsList == NULL) return (Qnil); for (xns = nsList; *xns != NULL; xns++) { VALUE ns = rxml_namespace_wrap(*xns); rb_yield(ns); } xmlFree(nsList); return Qnil; } /* * call-seq: * namespaces.find_by_href(href) -> XML::Namespace * * Searches for a namespace that has the specified href. * The search starts at the current node and works upward * through the node's parents. If a namespace is found, * then an XML::Namespace instance is returned, otherwise nil * is returned. * * Usage: * * doc = XML::Document.string('') * ns = doc.root.namespaces.find_by_href('http://schemas.xmlsoap.org/soap/envelope/') * assert_equal('soap', ns.prefix) * assert_equal('http://schemas.xmlsoap.org/soap/envelope/', ns.href) */ static VALUE rxml_namespaces_find_by_href(VALUE self, VALUE href) { xmlNodePtr xnode; xmlNsPtr xns; Check_Type(href, T_STRING); Data_Get_Struct(self, xmlNode, xnode); xns = xmlSearchNsByHref(xnode->doc, xnode, (xmlChar*) StringValuePtr(href)); if (xns) return rxml_namespace_wrap(xns); else return Qnil; } /* * call-seq: * namespaces.find_by_prefix(prefix=nil) -> XML::Namespace * * Searches for a namespace that has the specified prefix. * The search starts at the current node and works upward * through the node's parents. If a namespace is found, * then an XML::Namespace instance is returned, otherwise nil * is returned. * * Usage: * * doc = XML::Document.string('') * ns = doc.root.namespaces.find_by_prefix('soap') * assert_equal('soap', ns.prefix) * assert_equal('http://schemas.xmlsoap.org/soap/envelope/', ns.href) */ static VALUE rxml_namespaces_find_by_prefix(VALUE self, VALUE prefix) { xmlNodePtr xnode; xmlNsPtr xns; xmlChar* xprefix = NULL; if (!NIL_P(prefix)) { Check_Type(prefix, T_STRING); xprefix = (xmlChar*) StringValuePtr(prefix); } Data_Get_Struct(self, xmlNode, xnode); xns = xmlSearchNs(xnode->doc, xnode, xprefix); if (xns) return rxml_namespace_wrap(xns); else return Qnil; } /* * call-seq: * namespaces.namespace -> XML::Namespace * * Returns the current node's namespace. * * Usage: * * doc = XML::Document.string('') * ns = doc.root.namespaces.namespace * assert_equal('soap', ns.prefix) * assert_equal('http://schemas.xmlsoap.org/soap/envelope/', ns.href) */ static VALUE rxml_namespaces_namespace_get(VALUE self) { xmlNodePtr xnode; Data_Get_Struct(self, xmlNode, xnode); if (xnode->ns) return rxml_namespace_wrap(xnode->ns); else return Qnil; } /* * call-seq: * namespaces.namespace = XML::Namespace * * Sets the current node's namespace. * * Basic usage: * * # Create a node * node = XML::Node.new('Envelope') * * # Define the soap namespace - this does *not* put the node in the namespace * ns = XML::Namespace.new(node, 'soap', 'http://schemas.xmlsoap.org/soap/envelope/') * assert_equal("", node.to_s) * * # Now put the node in the soap namespace, not how the string representation changes * node.namespaces.namespace = ns * assert_equal("", node.to_s) */ static VALUE rxml_namespaces_namespace_set(VALUE self, VALUE ns) { xmlNodePtr xnode; xmlNsPtr xns; Data_Get_Struct(self, xmlNode, xnode); Check_Type(ns, T_DATA); Data_Get_Struct(ns, xmlNs, xns); xmlSetNs(xnode, xns); return self; } /* * call-seq: * namespaces.node -> XML::Node * * Returns the current node. */ static VALUE rxml_namespaces_node_get(VALUE self) { xmlNodePtr xnode; Data_Get_Struct(self, xmlNode, xnode); return rxml_node_wrap(xnode); } void rxml_init_namespaces(void) { cXMLNamespaces = rb_define_class_under(mXML, "Namespaces", rb_cObject); rb_include_module(cXMLNamespaces, rb_mEnumerable); rb_define_alloc_func(cXMLNamespaces, rxml_namespaces_alloc); rb_define_method(cXMLNamespaces, "initialize", rxml_namespaces_initialize, 1); rb_define_method(cXMLNamespaces, "definitions", rxml_namespaces_definitions, 0); rb_define_method(cXMLNamespaces, "each", rxml_namespaces_each, 0); rb_define_method(cXMLNamespaces, "find_by_href", rxml_namespaces_find_by_href, 1); rb_define_method(cXMLNamespaces, "find_by_prefix", rxml_namespaces_find_by_prefix, 1); rb_define_method(cXMLNamespaces, "namespace", rxml_namespaces_namespace_get, 0); rb_define_method(cXMLNamespaces, "namespace=", rxml_namespaces_namespace_set, 1); rb_define_method(cXMLNamespaces, "node", rxml_namespaces_node_get, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml.c0000644000004100000410000003236114620142101020105 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml.h" #include VALUE mXML; /* * call-seq: * XML.catalog_dump -> true * * Dump all the global catalog content stdout. */ static VALUE rxml_catalog_dump(VALUE self) { xmlCatalogDump(stdout); return (Qtrue); } /* * call-seq: * XML.catalog_remove(catalog) -> true * * Remove the specified resource catalog. */ static VALUE rxml_catalog_remove(VALUE self, VALUE cat) { Check_Type(cat, T_STRING); xmlCatalogRemove((xmlChar *) StringValuePtr(cat)); return (Qtrue); } /* * call-seq: * XML.check_lib_versions -> true * * Check LIBXML version matches version the bindings * were compiled to. Throws an exception if not. */ static VALUE rxml_check_lib_versions(VALUE klass) { xmlCheckVersion(LIBXML_VERSION); return (Qtrue); } /* * call-seq: * XML.enabled_automata? -> (true|false) * * Determine whether libxml regexp automata support is enabled. */ static VALUE rxml_enabled_automata_q(VALUE klass) { #ifdef LIBXML_AUTOMATA_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_c14n? -> (true|false) * * Determine whether libxml 'canonical XML' support is enabled. * See "Canonical XML" (http://www.w3.org/TR/xml-c14n) */ static VALUE rxml_enabled_c14n_q(VALUE klass) { #ifdef LIBXML_C14N_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_catalog? -> (true|false) * * Determine whether libxml resource catalog support is enabled. */ static VALUE rxml_enabled_catalog_q(VALUE klass) { #ifdef LIBXML_CATALOG_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_debug? -> (true|false) * * Determine whether libxml debugging support is enabled. */ static VALUE rxml_enabled_debug_q(VALUE klass) { #ifdef LIBXML_DEBUG_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_docbook? -> (true|false) * * Determine whether libxml docbook support is enabled. */ static VALUE rxml_enabled_docbook_q(VALUE klass) { #ifdef LIBXML_DOCB_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_ftp? -> (true|false) * * Determine whether libxml ftp client support is enabled. */ static VALUE rxml_enabled_ftp_q(VALUE klass) { #ifdef LIBXML_FTP_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_http? -> (true|false) * * Determine whether libxml http client support is enabled. */ static VALUE rxml_enabled_http_q(VALUE klass) { #ifdef LIBXML_HTTP_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_html? -> (true|false) * * Determine whether libxml html support is enabled. */ static VALUE rxml_enabled_html_q(VALUE klass) { #ifdef LIBXML_HTML_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_iconv? -> (true|false) * * Determine whether libxml iconv support is enabled. */ static VALUE rxml_enabled_iconv_q(VALUE klass) { #ifdef LIBXML_ICONV_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_memory_debug? -> (true|false) * * Determine whether libxml memory location debugging support * is enabled. */ static VALUE rxml_enabled_memory_debug_location_q(VALUE klass) { #ifdef DEBUG_MEMORY_LOCATION return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_regexp? -> (true|false) * * Determine whether libxml regular expression support is enabled. */ static VALUE rxml_enabled_regexp_q(VALUE klass) { #ifdef LIBXML_REGEXP_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_schemas? -> (true|false) * * Determine whether libxml schema support is enabled. */ static VALUE rxml_enabled_schemas_q(VALUE klass) { #ifdef LIBXML_SCHEMAS_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_thread? -> (true|false) * * Determine whether thread-safe semantics support for libxml is enabled and * is used by this ruby extension. Threading support in libxml uses pthread * on Unix-like systems and Win32 threads on Windows. */ static VALUE rxml_enabled_thread_q(VALUE klass) { /* This won't be defined unless this code is compiled with _REENTRANT or __MT__ * defined or the compiler is in C99 mode. * * Note the relevant portion libxml/xmlversion.h on a thread-enabled build: * * #if defined(_REENTRANT) || defined(__MT__) || \ * (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0 >= 199506L)) * #define LIBXML_THREAD_ENABLED * #endif * */ #ifdef LIBXML_THREAD_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_unicode? -> (true|false) * * Determine whether libxml unicode support is enabled. */ static VALUE rxml_enabled_unicode_q(VALUE klass) { #ifdef LIBXML_UNICODE_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_xinclude? -> (true|false) * * Determine whether libxml xinclude support is enabled. */ static VALUE rxml_enabled_xinclude_q(VALUE klass) { #ifdef LIBXML_XINCLUDE_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_xpath? -> (true|false) * * Determine whether libxml xpath support is enabled. */ static VALUE rxml_enabled_xpath_q(VALUE klass) { #ifdef LIBXML_XPATH_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_xpointer? -> (true|false) * * Determine whether libxml xpointer support is enabled. */ static VALUE rxml_enabled_xpointer_q(VALUE klass) { #ifdef LIBXML_XPTR_ENABLED return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.enabled_zlib? -> (true|false) * * Determine whether libxml zlib support is enabled. */ static VALUE rxml_enabled_zlib_q(VALUE klass) { #ifdef HAVE_ZLIB_H return(Qtrue); #else return (Qfalse); #endif } /* * call-seq: * XML.default_tree_indent_string -> "string" * * Obtain the default string used by parsers to indent the XML tree * for output. */ static VALUE rxml_default_tree_indent_string_get(VALUE klass) { if (xmlTreeIndentString == NULL) return (Qnil); else return (rb_str_new2(xmlTreeIndentString)); } /* * call-seq: * XML.default_tree_indent_string = "string" * * Set the default string used by parsers to indent the XML tree * for output. */ static VALUE rxml_default_tree_indent_string_set(VALUE klass, VALUE string) { Check_Type(string, T_STRING); xmlTreeIndentString = (const char *)xmlStrdup((xmlChar *)StringValuePtr(string)); return (string); } /* * call-seq: * XML.default_compression -> (true|false) * * Determine whether parsers use Zlib compression by default * (requires libxml to be compiled with Zlib support). */ static VALUE rxml_default_compression_get(VALUE klass) { #ifdef HAVE_ZLIB_H return(INT2FIX(xmlGetCompressMode())); #else rb_warn("libxml was compiled without zlib support"); return (Qfalse); #endif } /* * call-seq: * XML.default_compression = true|false * * Controls whether parsers use Zlib compression by default * (requires libxml to be compiled with Zlib support). */ static VALUE rxml_default_compression_set(VALUE klass, VALUE num) { #ifdef HAVE_ZLIB_H Check_Type(num, T_FIXNUM); xmlSetCompressMode(FIX2INT(num)); return(num); #else rb_warn("libxml was compiled without zlib support"); return (Qfalse); #endif } /* * call-seq: * XML.default_save_no_empty_tags -> (true|false) * * Determine whether serializer outputs empty tags by default. */ static VALUE rxml_default_save_no_empty_tags_get(VALUE klass) { if (xmlSaveNoEmptyTags) return (Qtrue); else return (Qfalse); } /* * call-seq: * XML.default_save_no_empty_tags = true|false * * Controls whether serializer outputs empty tags by default. */ static VALUE rxml_default_save_no_empty_tags_set(VALUE klass, VALUE value) { if (value == Qfalse) { xmlSaveNoEmptyTags = 0; return (Qfalse); } else if (value == Qtrue) { xmlSaveNoEmptyTags = 1; return (Qtrue); } else { rb_raise(rb_eArgError, "Invalid argument, must be a boolean"); } } /* * call-seq: * XML.indent_tree_output -> (true|false) * * Determines whether XML output will be indented * (using the string supplied to +default_indent_tree_string+) */ static VALUE rxml_indent_tree_output_get(VALUE klass) { if (xmlIndentTreeOutput) return (Qtrue); else return (Qfalse); } /* * call-seq: * XML.indent_tree_output = true|false * * Controls whether XML output will be indented * (using the string supplied to +default_indent_tree_string+) */ static VALUE rxml_indent_tree_output_set(VALUE klass, VALUE value) { if (value == Qtrue) { xmlIndentTreeOutput = 1; return (Qtrue); } else if (value == Qfalse) { xmlIndentTreeOutput = 0; return (Qfalse); } else { rb_raise(rb_eArgError, "Invalid argument, must be boolean"); } } /* * call-seq: * XML.memory_dump -> (true|false) * * Perform a parser memory dump (requires memory debugging * support in libxml). */ static VALUE rxml_memory_dump(VALUE self) { #ifdef DEBUG_MEMORY_LOCATION xmlMemoryDump(); return(Qtrue); #else rb_warn("libxml was compiled without memory debugging support"); return (Qfalse); #endif } /* * call-seq: * XML.memory_used -> num_bytes * * Perform a parser memory dump (requires memory debugging * support in libxml). */ static VALUE rxml_memory_used(VALUE self) { #ifdef DEBUG_MEMORY_LOCATION return(INT2NUM(xmlMemUsed())); #else rb_warn("libxml was compiled without memory debugging support"); return (Qfalse); #endif } /* The libxml gem provides Ruby language bindings for GNOME's Libxml2 * XML toolkit. Refer to the README file to get started * and the LICENSE file for copyright and distribution information. */ void rxml_init_xml(void) { mXML = rb_define_module_under(mLibXML, "XML"); /* Constants */ rb_define_const(mXML, "LIBXML_VERSION", rb_str_new2(LIBXML_DOTTED_VERSION)); rb_define_const(mXML, "VERSION", rb_str_new2(RUBY_LIBXML_VERSION)); rb_define_const(mXML, "VERNUM", INT2NUM(RUBY_LIBXML_VERNUM)); rb_define_const(mXML, "XML_NAMESPACE", rb_str_new2((const char*) XML_XML_NAMESPACE)); rb_define_module_function(mXML, "enabled_automata?", rxml_enabled_automata_q, 0); rb_define_module_function(mXML, "enabled_c14n?", rxml_enabled_c14n_q, 0); rb_define_module_function(mXML, "enabled_catalog?", rxml_enabled_catalog_q, 0); rb_define_module_function(mXML, "enabled_debug?", rxml_enabled_debug_q, 0); rb_define_module_function(mXML, "enabled_docbook?", rxml_enabled_docbook_q, 0); rb_define_module_function(mXML, "enabled_ftp?", rxml_enabled_ftp_q, 0); rb_define_module_function(mXML, "enabled_http?", rxml_enabled_http_q, 0); rb_define_module_function(mXML, "enabled_html?", rxml_enabled_html_q, 0); rb_define_module_function(mXML, "enabled_iconv?", rxml_enabled_iconv_q, 0); rb_define_module_function(mXML, "enabled_memory_debug?", rxml_enabled_memory_debug_location_q, 0); rb_define_module_function(mXML, "enabled_regexp?", rxml_enabled_regexp_q, 0); rb_define_module_function(mXML, "enabled_schemas?", rxml_enabled_schemas_q, 0); rb_define_module_function(mXML, "enabled_thread?", rxml_enabled_thread_q, 0); rb_define_module_function(mXML, "enabled_unicode?", rxml_enabled_unicode_q, 0); rb_define_module_function(mXML, "enabled_xinclude?", rxml_enabled_xinclude_q, 0); rb_define_module_function(mXML, "enabled_xpath?", rxml_enabled_xpath_q, 0); rb_define_module_function(mXML, "enabled_xpointer?", rxml_enabled_xpointer_q, 0); rb_define_module_function(mXML, "enabled_zlib?", rxml_enabled_zlib_q, 0); rb_define_module_function(mXML, "catalog_dump", rxml_catalog_dump, 0); rb_define_module_function(mXML, "catalog_remove", rxml_catalog_remove, 1); rb_define_module_function(mXML, "check_lib_versions", rxml_check_lib_versions, 0); rb_define_module_function(mXML, "default_compression", rxml_default_compression_get, 0); rb_define_module_function(mXML, "default_compression=", rxml_default_compression_set, 1); rb_define_module_function(mXML, "default_tree_indent_string", rxml_default_tree_indent_string_get, 0); rb_define_module_function(mXML, "default_tree_indent_string=", rxml_default_tree_indent_string_set, 1); rb_define_module_function(mXML, "default_save_no_empty_tags", rxml_default_save_no_empty_tags_get, 0); rb_define_module_function(mXML, "default_save_no_empty_tags=", rxml_default_save_no_empty_tags_set, 1); rb_define_module_function(mXML, "indent_tree_output", rxml_indent_tree_output_get, 0); rb_define_module_function(mXML, "indent_tree_output=", rxml_indent_tree_output_set, 1); rb_define_module_function(mXML, "memory_dump", rxml_memory_dump, 0); rb_define_module_function(mXML, "memory_used", rxml_memory_used, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema.c0000644000004100000410000002607714620142101021434 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_schema.h" #include "ruby_xml_schema_type.h" #include "ruby_xml_schema_element.h" #include "ruby_xml_schema_attribute.h" #include "ruby_xml_schema_facet.h" #include typedef struct _xmlSchemaBucket xmlSchemaBucket; typedef xmlSchemaBucket *xmlSchemaBucketPtr; /** * xmlSchemaSchemaRelation: * * Used to create a graph of schema relationships. */ typedef struct _xmlSchemaSchemaRelation xmlSchemaSchemaRelation; typedef xmlSchemaSchemaRelation *xmlSchemaSchemaRelationPtr; struct _xmlSchemaSchemaRelation { xmlSchemaSchemaRelationPtr next; int type; /* E.g. XML_SCHEMA_SCHEMA_IMPORT */ const xmlChar *importNamespace; xmlSchemaBucketPtr bucket; }; struct _xmlSchemaBucket { int type; int flags; const xmlChar *schemaLocation; const xmlChar *origTargetNamespace; const xmlChar *targetNamespace; xmlDocPtr doc; xmlSchemaSchemaRelationPtr relations; int located; int parsed; int imported; int preserveDoc; xmlSchemaItemListPtr globals; /* Global components. */ xmlSchemaItemListPtr locals; /* Local components. */ }; /** * xmlSchemaImport: * (extends xmlSchemaBucket) * * Reflects a schema. Holds some information * about the schema and its toplevel components. Duplicate * toplevel components are not checked at this level. */ typedef struct _xmlSchemaImport xmlSchemaImport; typedef xmlSchemaImport *xmlSchemaImportPtr; struct _xmlSchemaImport { int type; /* Main OR import OR include. */ int flags; const xmlChar *schemaLocation; /* The URI of the schema document. */ /* For chameleon includes, @origTargetNamespace will be NULL */ const xmlChar *origTargetNamespace; /* * For chameleon includes, @targetNamespace will be the * targetNamespace of the including schema. */ const xmlChar *targetNamespace; xmlDocPtr doc; /* The schema node-tree. */ /* @relations will hold any included/imported/redefined schemas. */ xmlSchemaSchemaRelationPtr relations; int located; int parsed; int imported; int preserveDoc; xmlSchemaItemListPtr globals; xmlSchemaItemListPtr locals; /* The imported schema. */ xmlSchemaPtr schema; }; /* * Document-class: LibXML::XML::Schema * * The XML::Schema class is used to prepare XML Schemas for validation of xml * documents. * * Schemas can be created from XML documents, strinings or URIs using the * corresponding methods (new for URIs). * * Once a schema is prepared, an XML document can be validated by the * XML::Document#validate_schema method providing the XML::Schema object * as parameter. The method return true if the document validates, false * otherwise. * * Basic usage: * * # parse schema as xml document * schema_document = XML::Document.file('schema.rng') * * # prepare schema for validation * schema = XML::Schema.document(schema_document) * * # parse xml document to be validated * instance = XML::Document.file('instance.xml') * * # validate * instance.validate_schema(schema) */ VALUE cXMLSchema; static void rxml_schema_free(xmlSchemaPtr xschema) { xmlSchemaFree(xschema); } VALUE rxml_wrap_schema(xmlSchemaPtr xschema) { VALUE result; if (!xschema) rb_raise(rb_eArgError, "XML::Schema is required!"); result = Data_Wrap_Struct(cXMLSchema, NULL, rxml_schema_free, xschema); /* * Create these as instance variables to provide the output of inspect/to_str some * idea of what schema this class contains. */ rb_iv_set(result, "@target_namespace", QNIL_OR_STRING(xschema->targetNamespace)); rb_iv_set(result, "@name", QNIL_OR_STRING(xschema->name)); rb_iv_set(result, "@id", QNIL_OR_STRING(xschema->id)); rb_iv_set(result, "@version", QNIL_OR_STRING(xschema->name)); return result; } static VALUE rxml_schema_init(VALUE class, xmlSchemaParserCtxtPtr xparser) { xmlSchemaPtr xschema; xschema = xmlSchemaParse(xparser); xmlSchemaFreeParserCtxt(xparser); if (!xschema) rxml_raise(xmlGetLastError()); return rxml_wrap_schema(xschema); } /* * call-seq: * XML::Schema.initialize(schema_uri) -> schema * * Create a new schema from the specified URI. */ static VALUE rxml_schema_init_from_uri(VALUE class, VALUE uri) { xmlSchemaParserCtxtPtr xparser; Check_Type(uri, T_STRING); xmlResetLastError(); xparser = xmlSchemaNewParserCtxt(StringValuePtr(uri)); if (!xparser) rxml_raise(xmlGetLastError()); return rxml_schema_init(class, xparser); } /* * call-seq: * XML::Schema.document(document) -> schema * * Create a new schema from the specified document. */ static VALUE rxml_schema_init_from_document(VALUE class, VALUE document) { xmlDocPtr xdoc; xmlSchemaParserCtxtPtr xparser; Data_Get_Struct(document, xmlDoc, xdoc); xmlResetLastError(); xparser = xmlSchemaNewDocParserCtxt(xdoc); if (!xparser) rxml_raise(xmlGetLastError()); return rxml_schema_init(class, xparser); } /* * call-seq: * XML::Schema.from_string("schema_data") -> "value" * * Create a new schema using the specified string. */ static VALUE rxml_schema_init_from_string(VALUE class, VALUE schema_str) { xmlSchemaParserCtxtPtr xparser; Check_Type(schema_str, T_STRING); xmlResetLastError(); xparser = xmlSchemaNewMemParserCtxt(StringValuePtr(schema_str), (int)strlen(StringValuePtr(schema_str))); if (!xparser) rxml_raise(xmlGetLastError()); return rxml_schema_init(class, xparser); } /* * call-seq: * XML::Schema.document -> document * * Return the Schema XML Document */ static VALUE rxml_schema_document(VALUE self) { xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); return rxml_node_wrap(xmlDocGetRootElement(xschema->doc)); } static void scan_namespaces(xmlSchemaImportPtr ximport, VALUE array, const xmlChar *nsname) { xmlNodePtr xnode; xmlNsPtr xns; if (ximport->doc) { xnode = xmlDocGetRootElement(ximport->doc); xns = xnode->nsDef; while (xns) { VALUE namespace = rxml_namespace_wrap(xns); rb_ary_push(array, namespace); xns = xns->next; } } } /* * call-seq: * XML::Schema.namespaces -> array * * Returns an array of Namespaces defined by the schema */ static VALUE rxml_schema_namespaces(VALUE self) { VALUE result; xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); result = rb_ary_new(); xmlHashScan(xschema->schemasImports, (xmlHashScanner)scan_namespaces, (void *)result); return result; } static void scan_schema_element(xmlSchemaElementPtr xelement, VALUE hash, const xmlChar *name) { VALUE element = rxml_wrap_schema_element(xelement); rb_hash_aset(hash, rb_str_new2((const char*)name), element); } static VALUE rxml_schema_elements(VALUE self) { VALUE result = rb_hash_new(); xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); xmlHashScan(xschema->elemDecl, (xmlHashScanner)scan_schema_element, (void *)result); return result; } static void collect_imported_ns_elements(xmlSchemaImportPtr import, VALUE result, const xmlChar *name) { if (import->imported && import->schema) { VALUE elements = rb_hash_new(); xmlHashScan(import->schema->elemDecl, (xmlHashScanner)scan_schema_element, (void *)elements); rb_hash_aset(result, QNIL_OR_STRING(import->schema->targetNamespace), elements); } } /* * call-seq: * XML::Schema.imported_ns_elements -> hash * * Returns a hash by namespace of a hash of schema elements within the entire schema including imports */ static VALUE rxml_schema_imported_ns_elements(VALUE self) { xmlSchemaPtr xschema; VALUE result = rb_hash_new(); Data_Get_Struct(self, xmlSchema, xschema); if (xschema) { xmlHashScan(xschema->schemasImports, (xmlHashScanner)collect_imported_ns_elements, (void *)result); } return result; } static void scan_schema_type(xmlSchemaTypePtr xtype, VALUE hash, const xmlChar *name) { VALUE type = rxml_wrap_schema_type(xtype); rb_hash_aset(hash, rb_str_new2((const char*)name), type); } static VALUE rxml_schema_types(VALUE self) { VALUE result = rb_hash_new(); xmlSchemaPtr xschema; Data_Get_Struct(self, xmlSchema, xschema); if (xschema != NULL && xschema->typeDecl != NULL) { xmlHashScan(xschema->typeDecl, (xmlHashScanner)scan_schema_type, (void *)result); } return result; } static void collect_imported_types(xmlSchemaImportPtr import, VALUE result, const xmlChar *name) { if (import->imported && import->schema) { xmlHashScan(import->schema->typeDecl, (xmlHashScanner)scan_schema_type, (void *)result); } } /* * call-seq: * XML::Schema.imported_types -> hash * * Returns a hash of all types within the entire schema including imports */ static VALUE rxml_schema_imported_types(VALUE self) { xmlSchemaPtr xschema; VALUE result = rb_hash_new(); Data_Get_Struct(self, xmlSchema, xschema); if (xschema) { xmlHashScan(xschema->schemasImports, (xmlHashScanner)collect_imported_types, (void *)result); } return result; } static void collect_imported_ns_types(xmlSchemaImportPtr import, VALUE result, const xmlChar *name) { if (import->imported && import->schema) { VALUE types = rb_hash_new(); xmlHashScan(import->schema->typeDecl, (xmlHashScanner)scan_schema_type, (void *)types); rb_hash_aset(result, QNIL_OR_STRING(import->schema->targetNamespace), types); } } /* * call-seq: * XML::Schema.imported_ns_types -> hash * * Returns a hash by namespace of a hash of schema types within the entire schema including imports */ static VALUE rxml_schema_imported_ns_types(VALUE self) { xmlSchemaPtr xschema; VALUE result = rb_hash_new(); Data_Get_Struct(self, xmlSchema, xschema); if (xschema) { xmlHashScan(xschema->schemasImports, (xmlHashScanner)collect_imported_ns_types, (void *)result); } return result; } void rxml_init_schema(void) { cXMLSchema = rb_define_class_under(mXML, "Schema", rb_cObject); rb_undef_alloc_func(cXMLSchema); rb_define_singleton_method(cXMLSchema, "new", rxml_schema_init_from_uri, 1); rb_define_singleton_method(cXMLSchema, "from_string", rxml_schema_init_from_string, 1); rb_define_singleton_method(cXMLSchema, "document", rxml_schema_init_from_document, 1); /* Create attr_reader methods for the above instance variables */ rb_define_attr(cXMLSchema, "target_namespace", 1, 0); rb_define_attr(cXMLSchema, "name", 1, 0); rb_define_attr(cXMLSchema, "id", 1, 0); rb_define_attr(cXMLSchema, "version", 1, 0); // These are just methods so as to hide their values and not overly clutter the output of inspect/to_str rb_define_method(cXMLSchema, "document", rxml_schema_document, 0); rb_define_method(cXMLSchema, "namespaces", rxml_schema_namespaces, 0); rb_define_method(cXMLSchema, "elements", rxml_schema_elements, 0); rb_define_method(cXMLSchema, "imported_ns_elements", rxml_schema_imported_ns_elements, 0); rb_define_method(cXMLSchema, "types", rxml_schema_types, 0); rb_define_method(cXMLSchema, "imported_types", rxml_schema_imported_types, 0); rb_define_method(cXMLSchema, "imported_ns_types", rxml_schema_imported_ns_types, 0); rxml_init_schema_facet(); rxml_init_schema_element(); rxml_init_schema_attribute(); rxml_init_schema_type(); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema_attribute.h0000644000004100000410000000174514620142101023517 0ustar www-datawww-data#ifndef __RXML_SCHEMA_ATTRIBUTE__ #define __RXML_SCHEMA_ATTRIBUTE__ #include "ruby_xml_schema.h" extern VALUE cXMLSchemaAttribute; /** * xmlSchemaAttributeUsePtr: * * The abstract base type for tree-like structured schema components. * (Extends xmlSchemaTreeItem) */ typedef struct _xmlSchemaAttributeUse xmlSchemaAttributeUse; typedef xmlSchemaAttributeUse *xmlSchemaAttributeUsePtr; struct _xmlSchemaAttributeUse { xmlSchemaTypeType type; xmlSchemaAnnotPtr annot; xmlSchemaAttributeUsePtr next; /* The next attr. use. */ /* * The attr. decl. OR a QName-ref. to an attr. decl. OR * a QName-ref. to an attribute group definition. */ xmlSchemaAttributePtr attrDecl; int flags; xmlNodePtr node; int occurs; /* required, optional */ const xmlChar *defValue; xmlSchemaValPtr defVal; }; void rxml_init_schema_attribute(void); VALUE rxml_wrap_schema_attribute(xmlSchemaAttributeUsePtr attr); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_dtd.c0000644000004100000410000001575514620142101020750 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_dtd.h" /* * Document-class: LibXML::XML::Dtd * * The XML::Dtd class is used to prepare DTD's for validation of xml * documents. * * DTDs can be created from a string or a pair of public and system identifiers. * Once a Dtd object is instantiated, an XML document can be validated by the * XML::Document#validate method providing the XML::Dtd object as parameeter. * The method will raise an exception if the document is * not valid. * * Basic usage: * * # parse DTD * dtd = XML::Dtd.new(< * * EOF * * # parse xml document to be validated * instance = XML::Document.file('instance.xml') * * # validate * instance.validate(dtd) */ VALUE cXMLDtd; void rxml_dtd_free(xmlDtdPtr xdtd) { if (xdtd->doc == NULL && xdtd->parent == NULL) xmlFreeDtd(xdtd); } void rxml_dtd_mark(xmlDtdPtr xdtd) { if (xdtd && xdtd->doc) { VALUE doc = (VALUE)xdtd->doc->_private; rb_gc_mark(doc); } } static VALUE rxml_dtd_alloc(VALUE klass) { return Data_Wrap_Struct(klass, rxml_dtd_mark, rxml_dtd_free, NULL); } VALUE rxml_dtd_wrap(xmlDtdPtr xdtd) { return Data_Wrap_Struct(cXMLDtd, NULL, NULL, xdtd); } /* * call-seq: * dtd.external_id -> "string" * * Obtain this dtd's external identifer (for a PUBLIC DTD). */ static VALUE rxml_dtd_external_id_get(VALUE self) { xmlDtdPtr xdtd; Data_Get_Struct(self, xmlDtd, xdtd); if (xdtd->ExternalID == NULL) return (Qnil); else return (rxml_new_cstr( xdtd->ExternalID, NULL)); } /* * call-seq: * dtd.name -> "string" * * Obtain this dtd's name. */ static VALUE rxml_dtd_name_get(VALUE self) { xmlDtdPtr xdtd; Data_Get_Struct(self, xmlDtd, xdtd); if (xdtd->name == NULL) return (Qnil); else return (rxml_new_cstr( xdtd->name, NULL)); } /* * call-seq: * dtd.uri -> "string" * * Obtain this dtd's URI (for a SYSTEM or PUBLIC DTD). */ static VALUE rxml_dtd_uri_get(VALUE self) { xmlDtdPtr xdtd; Data_Get_Struct(self, xmlDtd, xdtd); if (xdtd->SystemID == NULL) return (Qnil); else return (rxml_new_cstr( xdtd->SystemID, NULL)); } /* * call-seq: * node.type -> num * * Obtain this node's type identifier. */ static VALUE rxml_dtd_type(VALUE self) { xmlDtdPtr xdtd; Data_Get_Struct(self, xmlDtd, xdtd); return (INT2NUM(xdtd->type)); } /* * call-seq: * XML::Dtd.new(dtd_string) -> dtd * XML::Dtd.new(external_id, system_id) -> dtd * XML::Dtd.new(external_id, system_id, name, document, internal) -> dtd * * Create a new Dtd from the specified public and system identifiers: * * * The first usage creates a DTD from a string and requires 1 parameter. * * The second usage loads and parses an external DTD and requires 2 parameters. * * The third usage creates a new internal or external DTD and requires 2 parameters and 3 optional parameters. * The DTD is then attached to the specified document if it is not nil. * * Parameters: * * dtd_string - A string that contains a complete DTD * external_id - A string that specifies the DTD's external name. For example, "-//W3C//DTD XHTML 1.0 Transitional//EN" * system_id - A string that specififies the DTD's system name. For example, "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" * name - A string that specifies the DTD's name. For example "xhtml1". * document - A xml document. * internal - Boolean value indicating whether this is an internal or external DTD. Optional. If not specified * then external is assumed. */ static VALUE rxml_dtd_initialize(int argc, VALUE *argv, VALUE self) { xmlDtdPtr xdtd; VALUE external, system; switch (argc) { case 3: case 4: case 5: { const xmlChar *xname = NULL, *xpublic = NULL, *xsystem = NULL; xmlDocPtr xdoc = NULL; VALUE name, doc, internal; rb_scan_args(argc, argv, "23", &external, &system, &name, &doc, &internal); Check_Type(external, T_STRING); xpublic = (const xmlChar*) StringValuePtr(external); Check_Type(system, T_STRING); xsystem = (const xmlChar*) StringValuePtr(system); if (name != Qnil) { Check_Type(name, T_STRING); xname = (const xmlChar*)StringValuePtr(name); } if (doc != Qnil) { if (rb_obj_is_kind_of(doc, cXMLDocument) == Qfalse) rb_raise(rb_eTypeError, "Must pass an LibXML::XML::Document object"); Data_Get_Struct(doc, xmlDoc, xdoc); } if (internal == Qnil || internal == Qfalse) xdtd = xmlNewDtd(xdoc, xname, xpublic, xsystem); else xdtd = xmlCreateIntSubset(xdoc, xname, xpublic, xsystem); if (xdtd == NULL) rxml_raise(xmlGetLastError()); /* The document will free the dtd so Ruby should not */ RDATA(self)->dfree = NULL; DATA_PTR(self) = xdtd; xmlSetTreeDoc((xmlNodePtr) xdtd, xdoc); } break; case 2: { rb_scan_args(argc, argv, "20", &external, &system); Check_Type(external, T_STRING); Check_Type(system, T_STRING); xdtd = xmlParseDTD((xmlChar*) StringValuePtr(external), (xmlChar*) StringValuePtr(system)); if (xdtd == NULL) rxml_raise(xmlGetLastError()); DATA_PTR(self) = xdtd; xmlSetTreeDoc((xmlNodePtr) xdtd, NULL); break; } case 1: { VALUE dtd_string; rb_scan_args(argc, argv, "10", &dtd_string); Check_Type(dtd_string, T_STRING); /* Note that buffer is freed by xmlParserInputBufferPush*/ xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; xmlParserInputBufferPtr buffer = xmlAllocParserInputBuffer(enc); xmlChar *new_string = xmlStrdup((xmlChar*) StringValuePtr(dtd_string)); xmlParserInputBufferPush(buffer, xmlStrlen(new_string), (const char*) new_string); xdtd = xmlIOParseDTD(NULL, buffer, enc); if (xdtd == NULL) rxml_raise(xmlGetLastError()); xmlFree(new_string); DATA_PTR(self) = xdtd; break; } default: rb_raise(rb_eArgError, "wrong number of arguments"); } return self; } void rxml_init_dtd(void) { cXMLDtd = rb_define_class_under(mXML, "Dtd", rb_cObject); rb_define_alloc_func(cXMLDtd, rxml_dtd_alloc); rb_define_method(cXMLDtd, "initialize", rxml_dtd_initialize, -1); rb_define_method(cXMLDtd, "external_id", rxml_dtd_external_id_get, 0); rb_define_method(cXMLDtd, "name", rxml_dtd_name_get, 0); rb_define_method(cXMLDtd, "uri", rxml_dtd_uri_get, 0); rb_define_method(cXMLDtd, "node_type", rxml_dtd_type, 0); rb_define_alias(cXMLDtd, "system_id", "uri"); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_encoding.h0000644000004100000410000000112414620142101021751 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_ENCODING__ #define __RXML_ENCODING__ #include #include #include extern VALUE mXMLEncoding; void rxml_init_encoding(void); VALUE rxml_new_cstr(const xmlChar* xstr, const xmlChar* xencoding); VALUE rxml_new_cstr_len(const xmlChar* xstr, const long length, const xmlChar* xencoding); rb_encoding* rxml_xml_encoding_to_rb_encoding(VALUE klass, xmlCharEncoding xmlEncoding); rb_encoding* rxml_figure_encoding(const xmlChar* xencoding); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_parser_context.c0000644000004100000410000006556214620142101023236 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_parser_context.h" #include VALUE cXMLParserContext; static ID IO_ATTR; /* * Document-class: LibXML::XML::Parser::Context * * The XML::Parser::Context class provides in-depth control over how * a document is parsed. */ static void rxml_parser_context_free(xmlParserCtxtPtr ctxt) { xmlFreeParserCtxt(ctxt); } static VALUE rxml_parser_context_wrap(xmlParserCtxtPtr ctxt) { return Data_Wrap_Struct(cXMLParserContext, NULL, rxml_parser_context_free, ctxt); } static VALUE rxml_parser_context_alloc(VALUE klass) { xmlParserCtxtPtr ctxt = xmlNewParserCtxt(); return Data_Wrap_Struct(klass, NULL, rxml_parser_context_free, ctxt); } /* call-seq: * XML::Parser::Context.document(document) -> XML::Parser::Context * * Creates a new parser context based on the specified document. * * Parameters: * * document - An XML::Document instance * options - A or'ed together list of LibXML::XML::Parser::Options values */ static VALUE rxml_parser_context_document(int argc, VALUE* argv, VALUE klass) { VALUE document, options; rb_scan_args(argc, argv, "11", &document, &options); if (rb_obj_is_kind_of(document, cXMLDocument) == Qfalse) rb_raise(rb_eTypeError, "Must pass an LibXML::XML::Document object"); xmlDocPtr xdoc; xmlChar *buffer; int length; Data_Get_Struct(document, xmlDoc, xdoc); xmlDocDumpFormatMemoryEnc(xdoc, &buffer, &length, (const char*)xdoc->encoding, 0); xmlParserCtxtPtr ctxt = xmlCreateDocParserCtxt(buffer); if (!ctxt) rxml_raise(xmlGetLastError()); /* This is annoying, but xmlInitParserCtxt (called indirectly above) and xmlCtxtUseOptionsInternal (called below) initialize slightly different context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */ xmlCtxtUseOptions(ctxt, options == Qnil ? 0 : NUM2INT(options)); return rxml_parser_context_wrap(ctxt); } /* call-seq: * XML::Parser::Context.file(file) -> XML::Parser::Context * * Creates a new parser context based on the specified file or uri. * * Parameters: * * file - A filename or uri * options - A or'ed together list of LibXML::XML::Parser::Options values */ static VALUE rxml_parser_context_file(int argc, VALUE* argv, VALUE klass) { VALUE file, options; rb_scan_args(argc, argv, "11", &file, &options); xmlParserCtxtPtr ctxt = xmlCreateURLParserCtxt(StringValuePtr(file), 0); if (!ctxt) rxml_raise(xmlGetLastError()); /* This is annoying, but xmlInitParserCtxt (called indirectly above) and xmlCtxtUseOptionsInternal (called below) initialize slightly different context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */ xmlCtxtUseOptions(ctxt, options == Qnil ? 0 : NUM2INT(options)); return rxml_parser_context_wrap(ctxt); } /* call-seq: * XML::Parser::Context.string(string) -> XML::Parser::Context * * Creates a new parser context based on the specified string. * * Parameters: * * string - A string that contains the data to parse * options - A or'ed together list of LibXML::XML::Parser::Options values */ static VALUE rxml_parser_context_string(int argc, VALUE* argv, VALUE klass) { VALUE string, options; rb_scan_args(argc, argv, "11", &string, &options); Check_Type(string, T_STRING); if (RSTRING_LEN(string) == 0) rb_raise(rb_eArgError, "Must specify a string with one or more characters"); xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt(StringValuePtr(string), (int)RSTRING_LEN(string)); if (!ctxt) rxml_raise(xmlGetLastError()); /* This is annoying, but xmlInitParserCtxt (called indirectly above) and xmlCtxtUseOptionsInternal (called below) initialize slightly different context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */ xmlCtxtUseOptions(ctxt, options == Qnil ? 0 : NUM2INT(options)); return rxml_parser_context_wrap(ctxt); } /* call-seq: * XML::Parser::Context.io(io) -> XML::Parser::Context * * Creates a new parser context based on the specified io object. * * Parameters: * * io - A ruby IO object * options - A or'ed together list of LibXML::XML::Parser::Options values */ static VALUE rxml_parser_context_io(int argc, VALUE* argv, VALUE klass) { VALUE io, options; rb_scan_args(argc, argv, "11", &io, &options); if (NIL_P(io)) rb_raise(rb_eTypeError, "Must pass in an IO object"); xmlParserInputBufferPtr input = xmlParserInputBufferCreateIO((xmlInputReadCallback) rxml_read_callback, NULL, (void*)io, XML_CHAR_ENCODING_NONE); xmlParserCtxtPtr ctxt = xmlNewParserCtxt(); if (!ctxt) { xmlFreeParserInputBuffer(input); rxml_raise(xmlGetLastError()); } /* This is annoying, but xmlInitParserCtxt (called indirectly above) and xmlCtxtUseOptionsInternal (called below) initialize slightly different context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */ xmlCtxtUseOptions(ctxt, options == Qnil ? 0 : NUM2INT(options)); xmlParserInputPtr stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (!stream) { xmlFreeParserInputBuffer(input); xmlFreeParserCtxt(ctxt); rxml_raise(xmlGetLastError()); } inputPush(ctxt, stream); VALUE result = rxml_parser_context_wrap(ctxt); /* Attach io object to parser so it won't get freed.*/ rb_ivar_set(result, IO_ATTR, io); return result; } /* * call-seq: * context.base_uri -> "http:://libxml.org" * * Obtain the base url for this parser context. */ static VALUE rxml_parser_context_base_uri_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->input && ctxt->input->filename) return rxml_new_cstr((const xmlChar*)ctxt->input->filename, ctxt->encoding); else return Qnil; } /* * call-seq: * context.base_uri = "http:://libxml.org" * * Sets the base url for this parser context. */ static VALUE rxml_parser_context_base_uri_set(VALUE self, VALUE url) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); Check_Type(url, T_STRING); if (ctxt->input && !ctxt->input->filename) { const char* xurl = StringValuePtr(url); ctxt->input->filename = (const char*)xmlStrdup((const xmlChar*)xurl); } return self; } /* * call-seq: * context.close -> nil * * Closes the underlying input streams. This is useful when parsing a large amount of * files and you want to close the files without relying on Ruby's garbage collector * to run. */ static VALUE rxml_parser_context_close(VALUE self) { xmlParserCtxtPtr ctxt; xmlParserInputPtr xinput; Data_Get_Struct(self, xmlParserCtxt, ctxt); while ((xinput = inputPop(ctxt)) != NULL) { xmlFreeInputStream(xinput); } return Qnil; } /* * call-seq: * context.data_directory -> "dir" * * Obtain the data directory associated with this context. */ static VALUE rxml_parser_context_data_directory_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->directory == NULL) return (Qnil); else return (rxml_new_cstr((const xmlChar*)ctxt->directory, ctxt->encoding)); } /* * call-seq: * context.depth -> num * * Obtain the depth of this context. */ static VALUE rxml_parser_context_depth_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->depth)); } /* * call-seq: * context.disable_cdata? -> (true|false) * * Determine whether CDATA nodes will be created in this context. */ static VALUE rxml_parser_context_disable_cdata_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); /* LibXML controls this internally with the default SAX handler. */ if (ctxt->sax && ctxt->sax->cdataBlock) return (Qfalse); else return (Qtrue); } /* * call-seq: * context.disable_cdata = (true|false) * * Control whether CDATA nodes will be created in this context. */ static VALUE rxml_parser_context_disable_cdata_set(VALUE self, VALUE value) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->sax == NULL) rb_raise(rb_eRuntimeError, "Sax handler is not yet set"); /* LibXML controls this internally with the default SAX handler. */ if (value) ctxt->sax->cdataBlock = NULL; else ctxt->sax->cdataBlock = xmlSAX2CDataBlock; return value; } /* * call-seq: * context.disable_sax? -> (true|false) * * Determine whether SAX-based processing is disabled * in this context. */ static VALUE rxml_parser_context_disable_sax_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->disableSAX) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.docbook? -> (true|false) * * Determine whether this is a docbook context. */ static VALUE rxml_parser_context_docbook_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->html == 2) // TODO check this return (Qtrue); else return (Qfalse); } /* * call-seq: * context.encoding -> XML::Encoding::UTF_8 * * Obtain the character encoding identifier used in * this context. */ static VALUE rxml_parser_context_encoding_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return INT2NUM(xmlParseCharEncoding((const char*)ctxt->encoding)); } /* * call-seq: * context.encoding = XML::Encoding::UTF_8 * * Sets the character encoding for this context. */ static VALUE rxml_parser_context_encoding_set(VALUE self, VALUE encoding) { xmlParserCtxtPtr ctxt; int result; const char* xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(encoding)); xmlCharEncodingHandlerPtr hdlr = xmlFindCharEncodingHandler(xencoding); if (!hdlr) rb_raise(rb_eArgError, "Unknown encoding: %i", NUM2INT(encoding)); Data_Get_Struct(self, xmlParserCtxt, ctxt); result = xmlSwitchToEncoding(ctxt, hdlr); if (result != 0) rxml_raise(xmlGetLastError()); if (ctxt->encoding != NULL) xmlFree((xmlChar *) ctxt->encoding); ctxt->encoding = xmlStrdup((const xmlChar *) xencoding); return self; } /* * call-seq: * context.errno -> num * * Obtain the last-error number in this context. */ static VALUE rxml_parser_context_errno_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->errNo)); } /* * call-seq: * context.html? -> (true|false) * * Determine whether this is an html context. */ static VALUE rxml_parser_context_html_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->html == 1) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.max_num_streams -> num * * Obtain the limit on the number of IO streams opened in * this context. */ static VALUE rxml_parser_context_io_max_num_streams_get(VALUE self) { // TODO alias to max_streams and dep this? xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->inputMax)); } /* * call-seq: * context.num_streams -> "dir" * * Obtain the actual number of IO streams in this * context. */ static VALUE rxml_parser_context_io_num_streams_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->inputNr)); } /* * call-seq: * context.keep_blanks? -> (true|false) * * Determine whether parsers in this context retain * whitespace. */ static VALUE rxml_parser_context_keep_blanks_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->keepBlanks) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.name_depth -> num * * Obtain the name depth for this context. */ static VALUE rxml_parser_context_name_depth_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->nameNr)); } /* * call-seq: * context.name_depth_max -> num * * Obtain the maximum name depth for this context. */ static VALUE rxml_parser_context_name_depth_max_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->nameMax)); } /* * call-seq: * context.name_node -> "name" * * Obtain the name node for this context. */ static VALUE rxml_parser_context_name_node_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->name == NULL) return (Qnil); else return (rxml_new_cstr( ctxt->name, ctxt->encoding)); } /* * call-seq: * context.name_tab -> ["name", ..., "name"] * * Obtain the name table for this context. */ static VALUE rxml_parser_context_name_tab_get(VALUE self) { int i; xmlParserCtxtPtr ctxt; VALUE tab_ary; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->nameTab == NULL) return (Qnil); tab_ary = rb_ary_new(); for (i = (ctxt->nameNr - 1); i >= 0; i--) { if (ctxt->nameTab[i] == NULL) continue; else rb_ary_push(tab_ary, rxml_new_cstr( ctxt->nameTab[i], ctxt->encoding)); } return (tab_ary); } /* * call-seq: * context.node_depth -> num * * Obtain the node depth for this context. */ static VALUE rxml_parser_context_node_depth_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->nodeNr)); } /* * call-seq: * context.node -> node * * Obtain the root node of this context. */ static VALUE rxml_parser_context_node_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->node == NULL) return (Qnil); else return (rxml_node_wrap(ctxt->node)); } /* * call-seq: * context.node_depth_max -> num * * Obtain the maximum node depth for this context. */ static VALUE rxml_parser_context_node_depth_max_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->nodeMax)); } /* * call-seq: * context.num_chars -> num * * Obtain the number of characters in this context. */ static VALUE rxml_parser_context_num_chars_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (LONG2NUM(ctxt->nbChars)); } /* * call-seq: * context.options > XML::Parser::Options::NOENT * * Returns the parser options for this context. Multiple * options can be combined by using Bitwise OR (|). */ static VALUE rxml_parser_context_options_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return INT2NUM(ctxt->options); } /* * call-seq: * context.options = XML::Parser::Options::NOENT | XML::Parser::Options::NOCDATA * * Provides control over the execution of a parser. Valid values * are the constants defined on XML::Parser::Options. Multiple * options can be combined by using Bitwise OR (|). */ static VALUE rxml_parser_context_options_set(VALUE self, VALUE options) { xmlParserCtxtPtr ctxt; Check_Type(options, T_FIXNUM); Data_Get_Struct(self, xmlParserCtxt, ctxt); xmlCtxtUseOptions(ctxt, NUM2INT(options)); return self; } /* * call-seq: * context.recovery? -> (true|false) * * Determine whether recovery mode is enabled in this * context. */ static VALUE rxml_parser_context_recovery_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->recovery) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.recovery = true|false * * Control whether recovery mode is enabled in this * context. */ static VALUE rxml_parser_context_recovery_set(VALUE self, VALUE value) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (value == Qfalse) { ctxt->recovery = 0; return (Qfalse); } else { ctxt->recovery = 1; return (Qtrue); } } /* * call-seq: * context.replace_entities? -> (true|false) * * Determine whether external entity replacement is enabled in this * context. */ static VALUE rxml_parser_context_replace_entities_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->replaceEntities) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.replace_entities = true|false * * Control whether external entity replacement is enabled in this * context. */ static VALUE rxml_parser_context_replace_entities_set(VALUE self, VALUE value) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (value == Qfalse) { ctxt->replaceEntities = 0; return (Qfalse); } else { ctxt->replaceEntities = 1; return (Qtrue); } } /* * call-seq: * context.space_depth -> num * * Obtain the space depth for this context. */ static VALUE rxml_parser_context_space_depth_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->spaceNr)); } /* * call-seq: * context.space_depth -> num * * Obtain the maximum space depth for this context. */ static VALUE rxml_parser_context_space_depth_max_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); return (INT2NUM(ctxt->spaceMax)); } /* * call-seq: * context.subset_external? -> (true|false) * * Determine whether this context is a subset of an * external context. */ static VALUE rxml_parser_context_subset_external_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->inSubset == 2) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.subset_internal? -> (true|false) * * Determine whether this context is a subset of an * internal context. */ static VALUE rxml_parser_context_subset_internal_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->inSubset == 1) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.subset_internal_name -> "name" * * Obtain this context's subset name (valid only if * either of subset_external? or subset_internal? * is true). */ static VALUE rxml_parser_context_subset_name_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->intSubName == NULL) return (Qnil); else return (rxml_new_cstr(ctxt->intSubName, ctxt->encoding)); } /* * call-seq: * context.subset_external_uri -> "uri" * * Obtain this context's external subset URI. (valid only if * either of subset_external? or subset_internal? * is true). */ static VALUE rxml_parser_context_subset_external_uri_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->extSubURI == NULL) return (Qnil); else return (rxml_new_cstr( ctxt->extSubURI, ctxt->encoding)); } /* * call-seq: * context.subset_external_system_id -> "system_id" * * Obtain this context's external subset system identifier. * (valid only if either of subset_external? or subset_internal? * is true). */ static VALUE rxml_parser_context_subset_external_system_id_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->extSubSystem == NULL) return (Qnil); else return (rxml_new_cstr( ctxt->extSubSystem, ctxt->encoding)); } /* * call-seq: * context.standalone? -> (true|false) * * Determine whether this is a standalone context. */ static VALUE rxml_parser_context_standalone_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->standalone) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.stats? -> (true|false) * * Determine whether this context maintains statistics. */ static VALUE rxml_parser_context_stats_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->record_info) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.valid? -> (true|false) * * Determine whether this context is valid. */ static VALUE rxml_parser_context_valid_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->valid) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.validate? -> (true|false) * * Determine whether validation is enabled in this context. */ static VALUE rxml_parser_context_validate_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->validate) return (Qtrue); else return (Qfalse); } /* * call-seq: * context.version -> "version" * * Obtain this context's version identifier. */ static VALUE rxml_parser_context_version_get(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->version == NULL) return (Qnil); else return (rxml_new_cstr( ctxt->version, ctxt->encoding)); } /* * call-seq: * context.well_formed? -> (true|false) * * Determine whether this context contains well-formed XML. */ static VALUE rxml_parser_context_well_formed_q(VALUE self) { xmlParserCtxtPtr ctxt; Data_Get_Struct(self, xmlParserCtxt, ctxt); if (ctxt->wellFormed) return (Qtrue); else return (Qfalse); } void rxml_init_parser_context(void) { IO_ATTR = ID2SYM(rb_intern("@io")); cXMLParserContext = rb_define_class_under(cXMLParser, "Context", rb_cObject); rb_define_alloc_func(cXMLParserContext, rxml_parser_context_alloc); rb_define_singleton_method(cXMLParserContext, "document", rxml_parser_context_document, -1); rb_define_singleton_method(cXMLParserContext, "file", rxml_parser_context_file, -1); rb_define_singleton_method(cXMLParserContext, "io", rxml_parser_context_io, -1); rb_define_singleton_method(cXMLParserContext, "string", rxml_parser_context_string, -1); rb_define_method(cXMLParserContext, "base_uri", rxml_parser_context_base_uri_get, 0); rb_define_method(cXMLParserContext, "base_uri=", rxml_parser_context_base_uri_set, 1); rb_define_method(cXMLParserContext, "close", rxml_parser_context_close, 0); rb_define_method(cXMLParserContext, "data_directory", rxml_parser_context_data_directory_get, 0); rb_define_method(cXMLParserContext, "depth", rxml_parser_context_depth_get, 0); rb_define_method(cXMLParserContext, "disable_cdata?", rxml_parser_context_disable_cdata_q, 0); rb_define_method(cXMLParserContext, "disable_cdata=", rxml_parser_context_disable_cdata_set, 1); rb_define_method(cXMLParserContext, "disable_sax?", rxml_parser_context_disable_sax_q, 0); rb_define_method(cXMLParserContext, "docbook?", rxml_parser_context_docbook_q, 0); rb_define_method(cXMLParserContext, "encoding", rxml_parser_context_encoding_get, 0); rb_define_method(cXMLParserContext, "encoding=", rxml_parser_context_encoding_set, 1); rb_define_method(cXMLParserContext, "errno", rxml_parser_context_errno_get, 0); rb_define_method(cXMLParserContext, "html?", rxml_parser_context_html_q, 0); rb_define_method(cXMLParserContext, "io_max_num_streams", rxml_parser_context_io_max_num_streams_get, 0); rb_define_method(cXMLParserContext, "io_num_streams", rxml_parser_context_io_num_streams_get, 0); rb_define_method(cXMLParserContext, "keep_blanks?", rxml_parser_context_keep_blanks_q, 0); rb_define_method(cXMLParserContext, "name_node", rxml_parser_context_name_node_get, 0); rb_define_method(cXMLParserContext, "name_depth", rxml_parser_context_name_depth_get, 0); rb_define_method(cXMLParserContext, "name_depth_max", rxml_parser_context_name_depth_max_get, 0); rb_define_method(cXMLParserContext, "name_tab", rxml_parser_context_name_tab_get, 0); rb_define_method(cXMLParserContext, "node", rxml_parser_context_node_get, 0); rb_define_method(cXMLParserContext, "node_depth", rxml_parser_context_node_depth_get, 0); rb_define_method(cXMLParserContext, "node_depth_max", rxml_parser_context_node_depth_max_get, 0); rb_define_method(cXMLParserContext, "num_chars", rxml_parser_context_num_chars_get, 0); rb_define_method(cXMLParserContext, "options", rxml_parser_context_options_get, 0); rb_define_method(cXMLParserContext, "options=", rxml_parser_context_options_set, 1); rb_define_method(cXMLParserContext, "recovery?", rxml_parser_context_recovery_q, 0); rb_define_method(cXMLParserContext, "recovery=", rxml_parser_context_recovery_set, 1); rb_define_method(cXMLParserContext, "replace_entities?", rxml_parser_context_replace_entities_q, 0); rb_define_method(cXMLParserContext, "replace_entities=", rxml_parser_context_replace_entities_set, 1); rb_define_method(cXMLParserContext, "space_depth", rxml_parser_context_space_depth_get, 0); rb_define_method(cXMLParserContext, "space_depth_max", rxml_parser_context_space_depth_max_get, 0); rb_define_method(cXMLParserContext, "subset_external?", rxml_parser_context_subset_external_q, 0); rb_define_method(cXMLParserContext, "subset_external_system_id", rxml_parser_context_subset_external_system_id_get, 0); rb_define_method(cXMLParserContext, "subset_external_uri", rxml_parser_context_subset_external_uri_get, 0); rb_define_method(cXMLParserContext, "subset_internal?", rxml_parser_context_subset_internal_q, 0); rb_define_method(cXMLParserContext, "subset_internal_name", rxml_parser_context_subset_name_get, 0); rb_define_method(cXMLParserContext, "stats?", rxml_parser_context_stats_q, 0); rb_define_method(cXMLParserContext, "standalone?", rxml_parser_context_standalone_q, 0); rb_define_method(cXMLParserContext, "valid", rxml_parser_context_valid_q, 0); rb_define_method(cXMLParserContext, "validate?", rxml_parser_context_validate_q, 0); rb_define_method(cXMLParserContext, "version", rxml_parser_context_version_get, 0); rb_define_method(cXMLParserContext, "well_formed?", rxml_parser_context_well_formed_q, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_html_parser_options.h0000644000004100000410000000037214620142101024262 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_HTML_PARSER_OPTIONS__ #define __RXML_HTML_PARSER_OPTIONS__ extern VALUE mXMLHtmlParserOptions; void rxml_init_html_parser_options(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_namespace.c0000644000004100000410000001040514620142101022114 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_namespace.h" VALUE cXMLNamespace; /* Document-class: LibXML::XML::Namespace * * The Namespace class represents an XML namespace. * To add a namespace to a node, create a new instance * of this class. Note that this does *not* assign the * node to the namespace. To do that see the * XML::Namespaces#namespace method. * * Usage: * * node = XML::Node.new('') * XML::Namespace.new(node, 'soap', 'http://schemas.xmlsoap.org/soap/envelope/') * assert_equal("", node.to_s) * assert_nil(node.namespaces.namespace) */ /* Namespaces are owned and freed by their nodes. Thus, its easier for the ruby bindings to not manage attribute memory management. */ static VALUE rxml_namespace_alloc(VALUE klass) { return Data_Wrap_Struct(klass, NULL, NULL, NULL); } VALUE rxml_namespace_wrap(xmlNsPtr xns) { return Data_Wrap_Struct(cXMLNamespace, NULL, NULL, xns); } /* * call-seq: * initialize(node, "prefix", "href") -> XML::Namespace * * Create a new namespace and adds it to the specified node. * Note this does *not* assign the node to the namespace. * To do that see the XML::Namespaces#namespace method. */ static VALUE rxml_namespace_initialize(VALUE self, VALUE node, VALUE prefix, VALUE href) { xmlNodePtr xnode; xmlChar *xmlPrefix; xmlNsPtr xns; Check_Type(node, T_DATA); Data_Get_Struct(node, xmlNode, xnode); xmlResetLastError(); /* Prefix can be null - that means its the default namespace */ xmlPrefix = NIL_P(prefix) ? NULL : (xmlChar *)StringValuePtr(prefix); xns = xmlNewNs(xnode, (xmlChar*) StringValuePtr(href), xmlPrefix); DATA_PTR(self) = xns; return self; } /* * call-seq: * ns.href -> "href" * * Usage: * * doc = XML::Document.string('') * ns = doc.root.namespaces.find_by_href('http://schemas.xmlsoap.org/soap/envelope/') * assert_equal('http://schemas.xmlsoap.org/soap/envelope/', ns.href) */ static VALUE rxml_namespace_href_get(VALUE self) { xmlNsPtr xns; Data_Get_Struct(self, xmlNs, xns); if (xns->href == NULL) return Qnil; else return rxml_new_cstr( xns->href, NULL); } /* * call-seq: * ns.node_type -> num * * Obtain this namespace's type identifier. */ static VALUE rxml_namespace_node_type(VALUE self) { xmlNsPtr xns; Data_Get_Struct(self, xmlNs, xns); return INT2NUM(xns->type); } /* * call-seq: * ns.prefix -> "prefix" * * Obtain the namespace's prefix. * * Usage: * * doc = XML::Document.string('') * ns = doc.root.namespaces.find_by_href('http://schemas.xmlsoap.org/soap/envelope/') * assert_equal('soap', ns.prefix) */ static VALUE rxml_namespace_prefix_get(VALUE self) { xmlNsPtr xns; Data_Get_Struct(self, xmlNs, xns); if (xns->prefix == NULL) return Qnil; else return rxml_new_cstr( xns->prefix, NULL); } /* * call-seq: * ns.next -> XML::Namespace * * Obtain the next namespace. * * Usage: * * doc = XML::Document.string('') * ns = doc.root.namespaces.find_by_href('http://schemas.xmlsoap.org/soap/envelope/') * assert_nil(ns.next) */ static VALUE rxml_namespace_next(VALUE self) { xmlNsPtr xns; Data_Get_Struct(self, xmlNs, xns); if (xns == NULL || xns->next == NULL) return (Qnil); else return rxml_namespace_wrap(xns->next); } void rxml_init_namespace(void) { cXMLNamespace = rb_define_class_under(mXML, "Namespace", rb_cObject); rb_define_alloc_func(cXMLNamespace, rxml_namespace_alloc); rb_define_method(cXMLNamespace, "initialize", rxml_namespace_initialize, 3); rb_define_method(cXMLNamespace, "href", rxml_namespace_href_get, 0); rb_define_method(cXMLNamespace, "next", rxml_namespace_next, 0); rb_define_method(cXMLNamespace, "node_type", rxml_namespace_node_type, 0); rb_define_method(cXMLNamespace, "prefix", rxml_namespace_prefix_get, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_io.c0000644000004100000410000000231214620142101020565 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include static ID READ_METHOD; static ID WRITE_METHOD; /* This method is called by libxml when it wants to read more data from a stream. We go with the duck typing solution to support StringIO objects. */ int rxml_read_callback(void *context, char *buffer, int len) { VALUE io = (VALUE) context; VALUE string = rb_funcall(io, READ_METHOD, 1, INT2NUM(len)); size_t size; if (string == Qnil) return 0; size = RSTRING_LEN(string); memcpy(buffer, StringValuePtr(string), size); return (int)size; } int rxml_write_callback(VALUE io, const char *buffer, int len) { if (rb_io_check_io(io) == Qnil) { // Could be StringIO VALUE written, string; string = rb_external_str_new_with_enc(buffer, (long)strlen(buffer), rb_enc_get(io)); written = rb_funcall(io, WRITE_METHOD, 1, string); return NUM2INT(written); } else { return (int)rb_io_bufwrite(io, buffer, (size_t)len); } } void rxml_init_io(void) { READ_METHOD = rb_intern("read"); WRITE_METHOD = rb_intern("write"); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_xpath_object.c0000644000004100000410000002201114620142101022626 0ustar www-datawww-data#include "ruby_libxml.h" #include /* * Document-class: LibXML::XML::XPath::Object * * A collection of nodes returned from the evaluation of an XML::XPath * or XML::XPointer expression. */ VALUE cXMLXPathObject; /* Memory management of xpath results is tricky. If a nodeset is returned, it generally consists of pointers to nodes in the original document. However, namespace nodes are handled differently - libxml creates copies of them instead. Thus, when an xmlXPathObjectPtr is freed, libxml iterates over the results to find the copied namespace nodes to free them. This causes problems for the bindings because the underlying document may be freed before the xmlXPathObjectPtr instance. This might seem counterintuitive since the xmlXPathObjectPtr marks the document. However, once both objects go out of scope, the order of their destruction is random. To deal with this, the wrapper code searches for the namespace nodes and wraps them in Ruby objects. When the Ruby objects go out of scope then the namespace nodes are freed. */ static void rxml_xpath_object_free(rxml_xpath_object *rxpop) { /* We positively, absolutely cannot let libxml iterate over the nodeTab since if the underlying document has been freed the majority of entries are invalid, resulting in segmentation faults.*/ if (rxpop->xpop->nodesetval && rxpop->xpop->nodesetval->nodeTab) { xmlFree(rxpop->xpop->nodesetval->nodeTab); rxpop->xpop->nodesetval->nodeTab = NULL; } xmlXPathFreeObject(rxpop->xpop); xfree(rxpop); } /* Custom free function for copied namespace nodes */ static void rxml_xpath_namespace_free(xmlNsPtr xns) { xmlFreeNs(xns); } static void rxml_xpath_object_mark(rxml_xpath_object *rxpop) { VALUE doc = (VALUE)rxpop->xdoc->_private; rb_gc_mark(doc); rb_gc_mark(rxpop->nsnodes); } VALUE rxml_xpath_object_wrap(xmlDocPtr xdoc, xmlXPathObjectPtr xpop) { int i; rxml_xpath_object *rxpop = ALLOC(rxml_xpath_object); /* Make sure Ruby's GC can find the array in the stack */ VALUE nsnodes = rb_ary_new(); rxpop->xdoc =xdoc; rxpop->xpop = xpop; /* Find all the extra namespace nodes and wrap them. */ if (xpop->nodesetval && xpop->nodesetval->nodeNr) { for (i = 0; i < xpop->nodesetval->nodeNr; i++) { xmlNodePtr xnode = xpop->nodesetval->nodeTab[i]; if (xnode != NULL && xnode->type == XML_NAMESPACE_DECL) { VALUE ns = Qnil; xmlNsPtr xns = (xmlNsPtr)xnode; /* Get rid of libxml's -> next hack. The issue here is the rxml_namespace code assumes that ns->next refers to another namespace. */ xns->next = NULL; /* Specify a custom free function here since by default namespace nodes will not be freed */ ns = rxml_namespace_wrap((xmlNsPtr)xnode); RDATA(ns)->dfree = (RUBY_DATA_FUNC)rxml_xpath_namespace_free; rb_ary_push(nsnodes, ns); } } } rxpop->nsnodes = nsnodes; return Data_Wrap_Struct(cXMLXPathObject, rxml_xpath_object_mark, rxml_xpath_object_free, rxpop); } static VALUE rxml_xpath_object_tabref(xmlXPathObjectPtr xpop, int index) { if (index < 0) index = xpop->nodesetval->nodeNr + index; if (index < 0 || index + 1 > xpop->nodesetval->nodeNr) return Qnil; switch (xpop->nodesetval->nodeTab[index]->type) { case XML_ATTRIBUTE_NODE: return rxml_attr_wrap((xmlAttrPtr) xpop->nodesetval->nodeTab[index]); break; case XML_NAMESPACE_DECL: return rxml_namespace_wrap((xmlNsPtr)xpop->nodesetval->nodeTab[index]); break; default: return rxml_node_wrap(xpop->nodesetval->nodeTab[index]); } } /* * call-seq: * xpath_object.to_a -> [node, ..., node] * * Obtain an array of the nodes in this set. */ static VALUE rxml_xpath_object_to_a(VALUE self) { VALUE set_ary, nodeobj; rxml_xpath_object *rxpop; xmlXPathObjectPtr xpop; int i; Data_Get_Struct(self, rxml_xpath_object, rxpop); xpop = rxpop->xpop; set_ary = rb_ary_new(); if (!((xpop->nodesetval == NULL) || (xpop->nodesetval->nodeNr == 0))) { for (i = 0; i < xpop->nodesetval->nodeNr; i++) { nodeobj = rxml_xpath_object_tabref(xpop, i); rb_ary_push(set_ary, nodeobj); } } return (set_ary); } /* * call-seq: * xpath_object.empty? -> (true|false) * * Determine whether this nodeset is empty (contains no nodes). */ static VALUE rxml_xpath_object_empty_q(VALUE self) { rxml_xpath_object *rxpop; Data_Get_Struct(self, rxml_xpath_object, rxpop); if (rxpop->xpop->type != XPATH_NODESET) return Qnil; return (rxpop->xpop->nodesetval == NULL || rxpop->xpop->nodesetval->nodeNr <= 0) ? Qtrue : Qfalse; } /* * call-seq: * xpath_object.each { |node| ... } -> self * * Call the supplied block for each node in this set. */ static VALUE rxml_xpath_object_each(VALUE self) { rxml_xpath_object *rxpop; int i; if (rxml_xpath_object_empty_q(self) == Qtrue) return Qnil; Data_Get_Struct(self, rxml_xpath_object, rxpop); for (i = 0; i < rxpop->xpop->nodesetval->nodeNr; i++) { rb_yield(rxml_xpath_object_tabref(rxpop->xpop, i)); } return (self); } /* * call-seq: * xpath_object.first -> node * * Returns the first node in this node set, or nil if none exist. */ static VALUE rxml_xpath_object_first(VALUE self) { rxml_xpath_object *rxpop; if (rxml_xpath_object_empty_q(self) == Qtrue) return Qnil; Data_Get_Struct(self, rxml_xpath_object, rxpop); return rxml_xpath_object_tabref(rxpop->xpop, 0); } /* * call-seq: * xpath_object.last -> node * * Returns the last node in this node set, or nil if none exist. */ static VALUE rxml_xpath_object_last(VALUE self) { rxml_xpath_object *rxpop; if (rxml_xpath_object_empty_q(self) == Qtrue) return Qnil; Data_Get_Struct(self, rxml_xpath_object, rxpop); return rxml_xpath_object_tabref(rxpop->xpop, -1); } /* * call-seq: * xpath_object[i] -> node * * array index into set of nodes */ static VALUE rxml_xpath_object_aref(VALUE self, VALUE aref) { rxml_xpath_object *rxpop; if (rxml_xpath_object_empty_q(self) == Qtrue) return Qnil; Data_Get_Struct(self, rxml_xpath_object, rxpop); return rxml_xpath_object_tabref(rxpop->xpop, NUM2INT(aref)); } /* * call-seq: * xpath_object.length -> num * * Obtain the length of the nodesetval node list. */ static VALUE rxml_xpath_object_length(VALUE self) { rxml_xpath_object *rxpop; if (rxml_xpath_object_empty_q(self) == Qtrue) return INT2FIX(0); Data_Get_Struct(self, rxml_xpath_object, rxpop); return INT2NUM(rxpop->xpop->nodesetval->nodeNr); } /* * call-seq: * xpath_object.xpath_type -> int * * Returns the XPath type of the result object. * Possible values are defined as constants * on the XML::XPath class and include: * * * XML::XPath::UNDEFINED * * XML::XPath::NODESET * * XML::XPath::BOOLEAN * * XML::XPath::NUMBER * * XML::XPath::STRING * * XML::XPath::POINT * * XML::XPath::RANGE * * XML::XPath::LOCATIONSET * * XML::XPath::USERS * * XML::XPath::XSLT_TREE */ static VALUE rxml_xpath_object_get_type(VALUE self) { rxml_xpath_object *rxpop; Data_Get_Struct(self, rxml_xpath_object, rxpop); return INT2FIX(rxpop->xpop->type); } /* * call-seq: * xpath_object.string -> String * * Returns the original XPath expression as a string. */ static VALUE rxml_xpath_object_string(VALUE self) { rxml_xpath_object *rxpop; Data_Get_Struct(self, rxml_xpath_object, rxpop); if (rxpop->xpop->stringval == NULL) return Qnil; return rxml_new_cstr( rxpop->xpop->stringval, rxpop->xdoc->encoding); } /* * call-seq: * nodes.debug -> (true|false) * * Dump libxml debugging information to stdout. * Requires Libxml be compiled with debugging enabled. */ static VALUE rxml_xpath_object_debug(VALUE self) { #ifdef LIBXML_DEBUG_ENABLED rxml_xpath_object *rxpop; Data_Get_Struct(self, rxml_xpath_object, rxpop); xmlXPathDebugDumpObject(stdout, rxpop->xpop, 0); return Qtrue; #else rb_warn("libxml was compiled without debugging support."); return Qfalse; #endif } void rxml_init_xpath_object(void) { cXMLXPathObject = rb_define_class_under(mXPath, "Object", rb_cObject); rb_undef_alloc_func(cXMLXPathObject); rb_include_module(cXMLXPathObject, rb_mEnumerable); rb_define_attr(cXMLXPathObject, "context", 1, 0); rb_define_method(cXMLXPathObject, "each", rxml_xpath_object_each, 0); rb_define_method(cXMLXPathObject, "xpath_type", rxml_xpath_object_get_type, 0); rb_define_method(cXMLXPathObject, "empty?", rxml_xpath_object_empty_q, 0); rb_define_method(cXMLXPathObject, "first", rxml_xpath_object_first, 0); rb_define_method(cXMLXPathObject, "last", rxml_xpath_object_last, 0); rb_define_method(cXMLXPathObject, "length", rxml_xpath_object_length, 0); rb_define_method(cXMLXPathObject, "to_a", rxml_xpath_object_to_a, 0); rb_define_method(cXMLXPathObject, "[]", rxml_xpath_object_aref, 1); rb_define_method(cXMLXPathObject, "string", rxml_xpath_object_string, 0); rb_define_method(cXMLXPathObject, "debug", rxml_xpath_object_debug, 0); rb_define_alias(cXMLXPathObject, "size", "length"); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_dtd.h0000644000004100000410000000022314620142101020735 0ustar www-datawww-data#ifndef __RXML_DTD__ #define __RXML_DTD__ extern VALUE cXMLDtd; void rxml_init_dtd(void); VALUE rxml_dtd_wrap(xmlDtdPtr xdtd); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_reader.c0000644000004100000410000011316614620142101021432 0ustar www-datawww-data/* Copyright (c) 2006-2007 Apple Inc. * Please see the LICENSE file for copyright and distribution information. */ #include "ruby_libxml.h" #include "ruby_xml_reader.h" #include #include #include /* * Document-class: LibXML::XML::Reader * * The XML::Reader class provides a simpler, alternative way of parsing an XML * document in contrast to XML::Parser or XML::SaxParser. A XML::Reader instance * acts like a cursor going forward in a document stream, stopping at each node * it encounters. To advance to the next node, simply cadd XML::Reader#read. * * The XML::Reader API closely matches the DOM Core specification and supports * namespaces, xml:base, entity handling and DTDs. * * To summarize, XML::Reader provides a far simpler API to use versus XML::SaxParser * and is more memory efficient than using XML::Parser to create a DOM tree. * * Example: * * reader = XML::Reader.string("123") * reader.read * assert_equal('foo', reader.name) * assert_nil(reader.value) * * 3.times do |i| * reader.read * assert_equal(XML::Reader::TYPE_ELEMENT, reader.node_type) * assert_equal('bar', reader.name) * reader.read * assert_equal(XML::Reader::TYPE_TEXT, reader.node_type) * assert_equal((i + 1).to_s, reader.value) * reader.read * assert_equal(XML::Reader::TYPE_END_ELEMENT, reader.node_type) * end * * You can also parse documents (see XML::Reader.document), * strings (see XML::Parser.string) and io objects (see * XML::Parser.io). * * For a more in depth tutorial, albeit in C, see http://xmlsoft.org/xmlreader.html.*/ /* NOTE - We need to wrap the readers document to support Reader.read.node.find('/'). To do this we need to use xmlTextReaderCurrentDoc which means we have to free the document ourselves. Annoying... */ VALUE cXMLReader; static ID BASE_URI_SYMBOL; static ID ENCODING_SYMBOL; static ID IO_ATTR; static ID OPTIONS_SYMBOL; static void rxml_reader_free(xmlTextReaderPtr xreader) { xmlFreeTextReader(xreader); } static void rxml_reader_mark(xmlTextReaderPtr xreader) { xmlDocPtr xdoc = xmlTextReaderCurrentDoc(xreader); VALUE doc = (VALUE)xdoc->_private; rb_gc_mark(doc); } static VALUE rxml_reader_wrap(xmlTextReaderPtr xreader) { return Data_Wrap_Struct(cXMLReader, NULL, rxml_reader_free, xreader); } static xmlTextReaderPtr rxml_text_reader_get(VALUE obj) { xmlTextReaderPtr xreader; Data_Get_Struct(obj, xmlTextReader, xreader); return xreader; } /* * call-seq: * XML::Reader.document(doc) -> XML::Reader * * Create an new reader for the specified document. */ VALUE rxml_reader_document(VALUE klass, VALUE doc) { xmlDocPtr xdoc; xmlTextReaderPtr xreader; Data_Get_Struct(doc, xmlDoc, xdoc); xreader = xmlReaderWalker(xdoc); if (xreader == NULL) rxml_raise(xmlGetLastError()); return rxml_reader_wrap(xreader); } /* call-seq: * XML::Reader.file(path) -> XML::Reader * XML::Reader.file(path, :encoding => XML::Encoding::UTF_8, * :options => XML::Parser::Options::NOENT) -> XML::Parser * * Creates a new reader by parsing the specified file or uri. * * You may provide an optional hash table to control how the * parsing is performed. Valid options are: * * encoding - The document encoding, defaults to nil. Valid values * are the encoding constants defined on XML::Encoding. * options - Controls the execution of the parser, defaults to 0. * Valid values are the constants defined on * XML::Parser::Options. Mutliple options can be combined * by using Bitwise OR (|). */ static VALUE rxml_reader_file(int argc, VALUE *argv, VALUE klass) { VALUE path; VALUE options; rb_scan_args(argc, argv, "11", &path, &options); Check_Type(path, T_STRING); const char* xencoding = NULL; int xoptions = 0; if (!NIL_P(options)) { Check_Type(options, T_HASH); VALUE encoding = rb_hash_aref(options, BASE_URI_SYMBOL); xencoding = NIL_P(encoding) ? NULL : xmlGetCharEncodingName(NUM2INT(encoding)); VALUE parserOptions = rb_hash_aref(options, OPTIONS_SYMBOL); xoptions = NIL_P(parserOptions) ? 0 : NUM2INT(parserOptions); } xmlTextReaderPtr xreader = xmlReaderForFile(StringValueCStr(path), xencoding, xoptions); // Unfortunately libxml2 does not set xmlLastError and just returns a null reader if (xreader == NULL) rb_syserr_fail(ENOENT, StringValueCStr(path)); return rxml_reader_wrap(xreader); } /* call-seq: * XML::Reader.io(io) -> XML::Reader * XML::Reader.io(io, :encoding => XML::Encoding::UTF_8, * :options => XML::Parser::Options::NOENT) -> XML::Parser * * Creates a new reader by parsing the specified io object. * * You may provide an optional hash table to control how the * parsing is performed. Valid options are: * * base_uri - The base url for the parsed document. * encoding - The document encoding, defaults to nil. Valid values * are the encoding constants defined on XML::Encoding. * options - Controls the execution of the parser, defaults to 0. * Valid values are the constants defined on * XML::Parser::Options. Mutliple options can be combined * by using Bitwise OR (|). */ static VALUE rxml_reader_io(int argc, VALUE *argv, VALUE klass) { xmlTextReaderPtr xreader; VALUE result; VALUE io; VALUE options; char *xbaseurl = NULL; const char *xencoding = NULL; int xoptions = 0; rb_scan_args(argc, argv, "11", &io, &options); if (!NIL_P(options)) { VALUE baseurl = Qnil; VALUE encoding = Qnil; VALUE parserOptions = Qnil; Check_Type(options, T_HASH); baseurl = rb_hash_aref(options, BASE_URI_SYMBOL); xbaseurl = NIL_P(baseurl) ? NULL : StringValueCStr(baseurl); encoding = rb_hash_aref(options, ENCODING_SYMBOL); xencoding = NIL_P(encoding) ? NULL : xmlGetCharEncodingName(NUM2INT(encoding)); parserOptions = rb_hash_aref(options, OPTIONS_SYMBOL); xoptions = NIL_P(parserOptions) ? 0 : NUM2INT(parserOptions); } xreader = xmlReaderForIO((xmlInputReadCallback) rxml_read_callback, NULL, (void *) io, xbaseurl, xencoding, xoptions); if (xreader == NULL) rxml_raise(xmlGetLastError()); result = rxml_reader_wrap(xreader); /* Attach io object to parser so it won't get freed.*/ rb_ivar_set(result, IO_ATTR, io); return result; } /* call-seq: * XML::Reader.string(io) -> XML::Reader * XML::Reader.string(io, :encoding => XML::Encoding::UTF_8, * :options => XML::Parser::Options::NOENT) -> XML::Parser * * Creates a new reader by parsing the specified string. * * You may provide an optional hash table to control how the * parsing is performed. Valid options are: * * base_uri - The base url for the parsed document. * encoding - The document encoding, defaults to nil. Valid values * are the encoding constants defined on XML::Encoding. * options - Controls the execution of the parser, defaults to 0. * Valid values are the constants defined on * XML::Parser::Options. Mutliple options can be combined * by using Bitwise OR (|). */ static VALUE rxml_reader_string(int argc, VALUE *argv, VALUE klass) { xmlTextReaderPtr xreader; VALUE string; VALUE options; char *xbaseurl = NULL; const char *xencoding = NULL; int xoptions = 0; rb_scan_args(argc, argv, "11", &string, &options); Check_Type(string, T_STRING); if (!NIL_P(options)) { VALUE baseurl = Qnil; VALUE encoding = Qnil; VALUE parserOptions = Qnil; Check_Type(options, T_HASH); baseurl = rb_hash_aref(options, BASE_URI_SYMBOL); xbaseurl = NIL_P(baseurl) ? NULL : StringValueCStr(baseurl); encoding = rb_hash_aref(options, ENCODING_SYMBOL); xencoding = NIL_P(encoding) ? NULL : xmlGetCharEncodingName(NUM2INT(encoding)); parserOptions = rb_hash_aref(options, OPTIONS_SYMBOL); xoptions = NIL_P(parserOptions) ? 0 : NUM2INT(parserOptions); } xreader = xmlReaderForMemory(StringValueCStr(string), (int)RSTRING_LEN(string), xbaseurl, xencoding, xoptions); if (xreader == NULL) rxml_raise(xmlGetLastError()); return rxml_reader_wrap(xreader); } /* * call-seq: * reader.close -> code * * This method releases any resources allocated by the current instance * changes the state to Closed and close any underlying input. */ static VALUE rxml_reader_close(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderClose(xreader)); } /* * call-seq: * reader.move_to_attribute_no(index) -> code * * Move the position of the current instance to the attribute with the * specified index relative to the containing element. */ static VALUE rxml_reader_move_to_attr_no(VALUE self, VALUE index) { int ret; xmlTextReaderPtr xreader; xreader = rxml_text_reader_get(self); ret = xmlTextReaderMoveToAttributeNo(xreader, FIX2INT(index)); return INT2FIX(ret); } /* * call-seq: * reader.move_to_attribute(localName) -> code * * Move the position of the current instance to the attribute with the * specified name relative to the containing element. */ static VALUE rxml_reader_move_to_attr(VALUE self, VALUE val) { int ret; xmlTextReaderPtr xreader; xreader = rxml_text_reader_get(self); ret = xmlTextReaderMoveToAttribute(xreader, (const xmlChar *) StringValueCStr(val)); return INT2FIX(ret); } /* * call-seq: * reader.move_to_attribute_ns(localName, namespaceURI) -> code * * Move the position of the current instance to the attribute with the * specified name and namespace relative to the containing element. */ static VALUE rxml_reader_move_to_attr_ns(VALUE self, VALUE name, VALUE ns) { int ret; xmlTextReaderPtr xreader; xreader = rxml_text_reader_get(self); ret = xmlTextReaderMoveToAttributeNs(xreader, (const xmlChar *) StringValueCStr(name), (const xmlChar *) StringValueCStr(ns)); return INT2FIX(ret); } /* * call-seq: * reader.move_to_first_attribute -> code * * Move the position of the current instance to the first attribute associated * with the current node. */ static VALUE rxml_reader_move_to_first_attr(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderMoveToFirstAttribute(xreader)); } /* * call-seq: * reader.move_to_next_attribute -> code * * Move the position of the current instance to the next attribute associated * with the current node. */ static VALUE rxml_reader_move_to_next_attr(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderMoveToNextAttribute(xreader)); } /* * call-seq: * reader.move_to_element -> code * * Move the position of the current instance to the node that contains the * current attribute node. */ static VALUE rxml_reader_move_to_element(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderMoveToElement(xreader)); } /* * call-seq: * reader.next -> code * * Skip to the node following the current one in document order while avoiding * the subtree if any. */ static VALUE rxml_reader_next(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderNext(xreader)); } /* * call-seq: * reader.next_sibling -> code * * Skip to the node following the current one in document order while avoiding * the subtree if any. Currently implemented only for Readers built on a * document. */ static VALUE rxml_reader_next_sibling(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderNextSibling(xreader)); } /* * call-seq: * reader.node -> XML::Node * * Returns the reader's current node. It will return * nil if Reader#read has not yet been called. * WARNING - Using this method is dangerous because the * the node may be destroyed on the next #read. */ static VALUE rxml_reader_node(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); xmlNodePtr xnode = xmlTextReaderCurrentNode(xreader); return xnode ? rxml_node_wrap(xnode) : Qnil; } /* * call-seq: * reader.node_type -> type * * Get the node type of the current node. Reference: * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html */ static VALUE rxml_reader_node_type(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderNodeType(xreader)); } /* * call-seq: * reader.normalization -> value * * The value indicating whether to normalize white space and attribute values. * Since attribute value and end of line normalizations are a MUST in the XML * specification only the value true is accepted. The broken bahaviour of * accepting out of range character entities like � is of course not * supported either. * * Return 1 or -1 in case of error. */ static VALUE rxml_reader_normalization(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderNormalization(xreader)); } /* * call-seq: * reader.read -> nil|true|false * * Causes the reader to move to the next node in the stream, exposing its properties. * * Returns true if a node was successfully read or false if there are no more * nodes to read. On errors, an exception is raised.*/ static VALUE rxml_reader_read(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); int result = xmlTextReaderRead(xreader); switch(result) { case -1: rxml_raise(xmlGetLastError()); return Qnil; break; case 0: return Qfalse; case 1: return Qtrue; default: rb_raise(rb_eRuntimeError, "xmlTextReaderRead did not return -1, 0 or 1. Return value was: %d", result); } } /* * call-seq: * reader.read_attribute_value -> code * * Parse an attribute value into one or more Text and EntityReference nodes. * * Return 1 in case of success, 0 if the reader was not positionned on an * attribute node or all the attribute values have been read, or -1 in case of * error. */ static VALUE rxml_reader_read_attr_value(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderReadAttributeValue(xreader)); } /* * call-seq: * reader.read_inner_xml -> data * * Read the contents of the current node, including child nodes and markup. * * Return a string containing the XML content, or nil if the current node is * neither an element nor attribute, or has no child nodes. */ static VALUE rxml_reader_read_inner_xml(VALUE self) { VALUE result = Qnil; xmlTextReaderPtr xReader = rxml_text_reader_get(self); xmlChar *xml = xmlTextReaderReadInnerXml(xReader); if (xml) { const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); result = rxml_new_cstr( xml, xencoding); xmlFree(xml); } return result; } /* * call-seq: * reader.read_outer_xml -> data * * Read the contents of the current node, including child nodes and markup. * * Return a string containing the XML content, or nil if the current node is * neither an element nor attribute, or has no child nodes. */ static VALUE rxml_reader_read_outer_xml(VALUE self) { VALUE result = Qnil; xmlTextReaderPtr xReader = rxml_text_reader_get(self); xmlChar *xml = xmlTextReaderReadOuterXml(xReader); if (xml) { const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); result = rxml_new_cstr( xml, xencoding); xmlFree(xml); } return result; } /* * call-seq: * reader.read_state -> state * * Get the read state of the reader. */ static VALUE rxml_reader_read_state(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderReadState(xreader)); } /* * call-seq: * reader.read_string -> string * * Read the contents of an element or a text node as a string. * * Return a string containing the contents of the Element or Text node, or nil * if the reader is positioned on any other type of node. */ static VALUE rxml_reader_read_string(VALUE self) { VALUE result = Qnil; xmlTextReaderPtr xReader = rxml_text_reader_get(self); xmlChar *xml = xmlTextReaderReadString(xReader); if (xml) { const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); result = rxml_new_cstr( xml, xencoding); xmlFree(xml); } return result; } /* * call-seq: * reader.relax_ng_validate(rng) -> boolean * * Use RelaxNG to validate the document as it is processed. Activation is only * possible before the first read. If +rng+ is nil, the RelaxNG validation is * desactivated. * * Return true in case the RelaxNG validation could be (des)activated and false in * case of error. */ static VALUE rxml_reader_relax_ng_validate(VALUE self, VALUE rng) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); xmlRelaxNGPtr xrelax; int status; Data_Get_Struct(rng, xmlRelaxNG, xrelax); status = xmlTextReaderRelaxNGSetSchema(xreader, xrelax); return (status == 0 ? Qtrue : Qfalse); } #if LIBXML_VERSION >= 20620 /* * call-seq: * reader.schema_validate(schema) -> boolean * * Use W3C XSD schema to validate the document as it is processed. Activation * is only possible before the first read. If +schema+ is nil, then XML Schema * validation is deactivated. * * Return false if if the schema's validation could be (de)activated and true * otherwise. */ static VALUE rxml_reader_schema_validate(VALUE self, VALUE xsd) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); xmlSchemaPtr xschema; int status; Data_Get_Struct(xsd, xmlSchema, xschema); status = xmlTextReaderSetSchema(xreader, xschema); return (status == 0 ? Qtrue : Qfalse); } #endif /* * call-seq: * reader.name -> name * * Return the qualified name of the node. */ static VALUE rxml_reader_name(VALUE self) { xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *result = xmlTextReaderConstName(xReader); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); return (result == NULL ? Qnil : rxml_new_cstr(result, xencoding)); } /* * call-seq: * reader.local_name -> name * * Return the local name of the node. */ static VALUE rxml_reader_local_name(VALUE self) { xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *result = xmlTextReaderConstLocalName(xReader); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); return (result == NULL ? Qnil : rxml_new_cstr(result, xencoding)); } /* * call-seq: * reader.attribute_count -> count * * Provide the number of attributes of the current node. */ static VALUE rxml_reader_attr_count(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderAttributeCount(xreader)); } /* * call-seq: * reader.encoding -> XML::Encoding::UTF_8 * * Returns the encoding of the document being read. Note you * first have to read data from the reader for encoding * to return a value * * reader = XML::Reader.file(XML_FILE) * assert_nil(reader.encoding) * reader.read * assert_equal(XML::Encoding::UTF_8, reader.encoding) * * In addition, libxml always appears to return nil for the encoding * when parsing strings. */ static VALUE rxml_reader_encoding(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); const xmlChar *xencoding = xmlTextReaderConstEncoding(xreader); if (xencoding) return INT2NUM(xmlParseCharEncoding((const char*)xencoding)); else return INT2NUM(XML_CHAR_ENCODING_NONE); } /* * call-seq: * reader.base_uri -> URI * * Determine the base URI of the node. */ static VALUE rxml_reader_base_uri(VALUE self) { xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *result = xmlTextReaderConstBaseUri(xReader); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); return (result == NULL ? Qnil : rxml_new_cstr(result, xencoding)); } /* * call-seq: * reader.namespace_uri -> URI * * Determine the namespace URI of the node. */ static VALUE rxml_reader_namespace_uri(VALUE self) { xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *result = xmlTextReaderConstNamespaceUri(xReader); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); return (result == NULL ? Qnil : rxml_new_cstr(result, xencoding)); } /* * call-seq: * reader.value -> text * * Provide the text value of the node if present. */ static VALUE rxml_reader_value(VALUE self) { xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *result = xmlTextReaderConstValue(xReader); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); return (result == NULL ? Qnil : rxml_new_cstr(result, xencoding)); } /* * call-seq: * reader.prefix -> prefix * * Get a shorthand reference to the namespace associated with the node. */ static VALUE rxml_reader_prefix(VALUE self) { xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *result = xmlTextReaderConstPrefix(xReader); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); return (result == NULL ? Qnil : rxml_new_cstr(result, xencoding)); } /* * call-seq: * reader.depth -> depth * * Get the depth of the node in the tree. */ static VALUE rxml_reader_depth(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderDepth(xreader)); } /* * call-seq: * reader.quote_char -> char * * Get the quotation mark character used to enclose the value of an attribute, * as an integer value (and -1 in case of error). */ static VALUE rxml_reader_quote_char(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderQuoteChar(xreader)); } /* * call-seq: * reader.standalone -> code * * Determine the standalone status of the document being read. * * Return 1 if the document was declared to be standalone, 0 if it was * declared to be not standalone, or -1 if the document did not specify its * standalone status or in case of error. */ static VALUE rxml_reader_standalone(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2FIX(xmlTextReaderStandalone(xreader)); } /* * call-seq: * reader.xml_lang -> value * * Get the xml:lang scope within which the node resides. */ static VALUE rxml_reader_xml_lang(VALUE self) { xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *result = xmlTextReaderConstXmlLang(xReader); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); return (result == NULL ? Qnil : rxml_new_cstr(result, xencoding)); } /* * call-seq: * reader.xml_version -> version * * Determine the XML version of the document being read. */ static VALUE rxml_reader_xml_version(VALUE self) { xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *result = xmlTextReaderConstXmlVersion(xReader); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); return (result == NULL ? Qnil : rxml_new_cstr(result, xencoding)); } /* * call-seq: * reader.has_attributes? -> bool * * Get whether the node has attributes. */ static VALUE rxml_reader_has_attributes(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return xmlTextReaderHasAttributes(xreader) ? Qtrue : Qfalse; } /* * call-seq: * reader.has_value? -> bool * * Get whether the node can have a text value. */ static VALUE rxml_reader_has_value(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return xmlTextReaderHasValue(xreader) ? Qtrue : Qfalse; } /* * call-seq: * reader[key] -> value * * Provide the value of the attribute with the specified index (if +key+ is an * integer) or with the specified name (if +key+ is a string) relative to the * containing element, as a string. */ static VALUE rxml_reader_attribute(VALUE self, VALUE key) { VALUE result = Qnil; xmlChar *xattr; xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); if (TYPE(key) == T_FIXNUM) { xattr = xmlTextReaderGetAttributeNo(xReader, FIX2INT(key)); } else { xattr = xmlTextReaderGetAttribute(xReader, (const xmlChar *) StringValueCStr(key)); } if (xattr) { result = rxml_new_cstr(xattr, xencoding); xmlFree(xattr); } return result; } /* * call-seq: * reader.get_attribute(localName) -> value * * Provide the value of the attribute with the specified name * relative to the containing element. */ static VALUE rxml_reader_get_attribute(VALUE self, VALUE name) { VALUE result = Qnil; xmlChar *xattr; xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); xattr = xmlTextReaderGetAttribute(xReader, (const xmlChar *) StringValueCStr(name)); if (xattr) { result = rxml_new_cstr(xattr, xencoding); xmlFree(xattr); } return result; } /* * call-seq: * reader.get_attribute_no(index) -> value * * Provide the value of the attribute with the specified index * relative to the containing element. */ static VALUE rxml_reader_get_attribute_no(VALUE self, VALUE index) { VALUE result = Qnil; xmlChar *xattr; xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); xattr = xmlTextReaderGetAttributeNo(xReader, FIX2INT(index)); if (xattr) { result = rxml_new_cstr(xattr, xencoding); xmlFree(xattr); } return result; } static VALUE rxml_reader_get_attribute_ns(VALUE self, VALUE name, VALUE ns) { VALUE result = Qnil; xmlChar *xattr; xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); xattr = xmlTextReaderGetAttributeNs(xReader, (const xmlChar *) StringValueCStr(name), (const xmlChar *) StringValueCStr(ns)); if (xattr) { result = rxml_new_cstr(xattr, xencoding); xmlFree(xattr); } return result; } /* * call-seq: * reader.lookup_namespace(prefix) -> value * * Resolve a namespace prefix in the scope of the current element. * To return the default namespace, specify nil as +prefix+. */ static VALUE rxml_reader_lookup_namespace(VALUE self, VALUE prefix) { VALUE result = Qnil; xmlTextReaderPtr xReader = rxml_text_reader_get(self); const xmlChar *xnamespace = xmlTextReaderLookupNamespace(xReader, (const xmlChar *) StringValueCStr(prefix)); const xmlChar *xencoding = xmlTextReaderConstEncoding(xReader); if (xnamespace) { result = rxml_new_cstr(xnamespace, xencoding); xmlFree((void *)xnamespace); } return result; } /* * call-seq: * reader.expand -> node * * Returns the current node and its full subtree. Note the returned node * is valid ONLY until the next read call. If you would like to preserve * the node, or search it via xpath, call reader.doc first. */ static VALUE rxml_reader_expand(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); xmlNodePtr xnode = xmlTextReaderExpand(xreader); if (!xnode) { return Qnil; } else { /* We cannot call rxml_node_wrap here because its sets up a mark function for the node. But according to the libxml docs (http://xmlsoft.org/html/libxml-xmlreader.html#xmlTextReaderExpand) this is only valid until the next xmlTextReaderRead call. At that point the node is freed (from reading the libxml2 source code. So don't set a mark or free function, because they will get called in the next garbage collection run and cause a segfault.*/ return Data_Wrap_Struct(cXMLNode, NULL, NULL, xnode); } } /* * call-seq: * reader.document -> doc * * Hacking interface that provides access to the current document being accessed by the * reader. NOTE: as a result of this call, the reader will not destroy the associated XML * document. Instead, it will be destroyed when the returned document goes out of scope. * * Returns: document */ static VALUE rxml_reader_doc(VALUE self) { VALUE result = Qnil; xmlTextReaderPtr xreader = rxml_text_reader_get(self); xmlDocPtr xdoc = xmlTextReaderCurrentDoc(xreader); if (!xdoc) rb_raise(rb_eRuntimeError, "The reader does not have a document. Did you forget to call read?"); result = rxml_document_wrap(xdoc); // And now hook in a mark function to keep the document alive as long as the reader is valid RDATA(self)->dmark = (RUBY_DATA_FUNC)rxml_reader_mark; return result; } #if LIBXML_VERSION >= 20618 /* * call-seq: * reader.byte_consumed -> value * * This method provides the current index of the parser used by the reader, * relative to the start of the current entity. */ static VALUE rxml_reader_byte_consumed(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return LONG2NUM(xmlTextReaderByteConsumed(xreader)); } #endif #if LIBXML_VERSION >= 20617 /* * call-seq: * reader.column_number -> number * * Provide the column number of the current parsing point. */ static VALUE rxml_reader_column_number(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2NUM(xmlTextReaderGetParserColumnNumber(xreader)); } /* * call-seq: * reader.line_number -> number * * Provide the line number of the current parsing point. */ static VALUE rxml_reader_line_number(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return INT2NUM(xmlTextReaderGetParserLineNumber(xreader)); } #endif /* * call-seq: * reader.default? -> bool * * Return whether an Attribute node was generated from the default value * defined in the DTD or schema. */ static VALUE rxml_reader_default(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return xmlTextReaderIsDefault(xreader) ? Qtrue : Qfalse; } /* * call-seq: * reader.namespace_declaration? -> bool * * Determine whether the current node is a namespace declaration rather than a * regular attribute. */ static VALUE rxml_reader_namespace_declaration(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return xmlTextReaderIsNamespaceDecl(xreader) ? Qtrue : Qfalse; } /* * call-seq: * reader.empty_element? -> bool * * Check if the current node is empty. */ static VALUE rxml_reader_empty_element(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return xmlTextReaderIsEmptyElement(xreader) ? Qtrue : Qfalse; } /* * call-seq: * reader.valid? -> bool * * Retrieve the validity status from the parser context. */ static VALUE rxml_reader_valid(VALUE self) { xmlTextReaderPtr xreader = rxml_text_reader_get(self); return xmlTextReaderIsValid(xreader) ? Qtrue : Qfalse; } void rxml_init_reader(void) { BASE_URI_SYMBOL = ID2SYM(rb_intern("base_uri")); ENCODING_SYMBOL = ID2SYM(rb_intern("encoding")); IO_ATTR = rb_intern("@io"); OPTIONS_SYMBOL = ID2SYM(rb_intern("options")); cXMLReader = rb_define_class_under(mXML, "Reader", rb_cObject); rb_undef_alloc_func(cXMLReader); rb_define_singleton_method(cXMLReader, "document", rxml_reader_document, 1); rb_define_singleton_method(cXMLReader, "file", rxml_reader_file, -1); rb_define_singleton_method(cXMLReader, "io", rxml_reader_io, -1); rb_define_singleton_method(cXMLReader, "string", rxml_reader_string, -1); rb_define_method(cXMLReader, "[]", rxml_reader_attribute, 1); rb_define_method(cXMLReader, "attribute_count", rxml_reader_attr_count, 0); rb_define_method(cXMLReader, "base_uri", rxml_reader_base_uri, 0); #if LIBXML_VERSION >= 20618 rb_define_method(cXMLReader, "byte_consumed", rxml_reader_byte_consumed, 0); #endif rb_define_method(cXMLReader, "close", rxml_reader_close, 0); #if LIBXML_VERSION >= 20617 rb_define_method(cXMLReader, "column_number", rxml_reader_column_number, 0); #endif rb_define_method(cXMLReader, "depth", rxml_reader_depth, 0); rb_define_method(cXMLReader, "doc", rxml_reader_doc, 0); rb_define_method(cXMLReader, "encoding", rxml_reader_encoding, 0); rb_define_method(cXMLReader, "expand", rxml_reader_expand, 0); rb_define_method(cXMLReader, "get_attribute", rxml_reader_get_attribute, 1); rb_define_method(cXMLReader, "get_attribute_no", rxml_reader_get_attribute_no, 1); rb_define_method(cXMLReader, "get_attribute_ns", rxml_reader_get_attribute_ns, 2); rb_define_method(cXMLReader, "has_attributes?", rxml_reader_has_attributes, 0); rb_define_method(cXMLReader, "has_value?", rxml_reader_has_value, 0); #if LIBXML_VERSION >= 20617 rb_define_method(cXMLReader, "line_number", rxml_reader_line_number, 0); #endif rb_define_method(cXMLReader, "local_name", rxml_reader_local_name, 0); rb_define_method(cXMLReader, "lookup_namespace", rxml_reader_lookup_namespace, 1); rb_define_method(cXMLReader, "move_to_attribute", rxml_reader_move_to_attr, 1); rb_define_method(cXMLReader, "move_to_attribute_no", rxml_reader_move_to_attr_no, 1); rb_define_method(cXMLReader, "move_to_attribute_ns", rxml_reader_move_to_attr_ns, 2); rb_define_method(cXMLReader, "move_to_first_attribute", rxml_reader_move_to_first_attr, 0); rb_define_method(cXMLReader, "move_to_next_attribute", rxml_reader_move_to_next_attr, 0); rb_define_method(cXMLReader, "move_to_element", rxml_reader_move_to_element, 0); rb_define_method(cXMLReader, "name", rxml_reader_name, 0); rb_define_method(cXMLReader, "namespace_uri", rxml_reader_namespace_uri, 0); rb_define_method(cXMLReader, "next", rxml_reader_next, 0); rb_define_method(cXMLReader, "next_sibling", rxml_reader_next_sibling, 0); rb_define_method(cXMLReader, "node", rxml_reader_node, 0); rb_define_method(cXMLReader, "node_type", rxml_reader_node_type, 0); rb_define_method(cXMLReader, "normalization", rxml_reader_normalization, 0); rb_define_method(cXMLReader, "prefix", rxml_reader_prefix, 0); rb_define_method(cXMLReader, "quote_char", rxml_reader_quote_char, 0); rb_define_method(cXMLReader, "read", rxml_reader_read, 0); rb_define_method(cXMLReader, "read_attribute_value", rxml_reader_read_attr_value, 0); rb_define_method(cXMLReader, "read_inner_xml", rxml_reader_read_inner_xml, 0); rb_define_method(cXMLReader, "read_outer_xml", rxml_reader_read_outer_xml, 0); rb_define_method(cXMLReader, "read_state", rxml_reader_read_state, 0); rb_define_method(cXMLReader, "read_string", rxml_reader_read_string, 0); rb_define_method(cXMLReader, "relax_ng_validate", rxml_reader_relax_ng_validate, 1); rb_define_method(cXMLReader, "standalone", rxml_reader_standalone, 0); #if LIBXML_VERSION >= 20620 rb_define_method(cXMLReader, "schema_validate", rxml_reader_schema_validate, 1); #endif rb_define_method(cXMLReader, "value", rxml_reader_value, 0); rb_define_method(cXMLReader, "xml_lang", rxml_reader_xml_lang, 0); rb_define_method(cXMLReader, "xml_version", rxml_reader_xml_version, 0); rb_define_method(cXMLReader, "default?", rxml_reader_default, 0); rb_define_method(cXMLReader, "empty_element?", rxml_reader_empty_element, 0); rb_define_method(cXMLReader, "namespace_declaration?", rxml_reader_namespace_declaration, 0); rb_define_method(cXMLReader, "valid?", rxml_reader_valid, 0); /* Constants */ rb_define_const(cXMLReader, "LOADDTD", INT2FIX(XML_PARSER_LOADDTD)); rb_define_const(cXMLReader, "DEFAULTATTRS", INT2FIX(XML_PARSER_DEFAULTATTRS)); rb_define_const(cXMLReader, "VALIDATE", INT2FIX(XML_PARSER_VALIDATE)); rb_define_const(cXMLReader, "SUBST_ENTITIES", INT2FIX(XML_PARSER_SUBST_ENTITIES)); rb_define_const(cXMLReader, "SEVERITY_VALIDITY_WARNING", INT2FIX(XML_PARSER_SEVERITY_VALIDITY_WARNING)); rb_define_const(cXMLReader, "SEVERITY_VALIDITY_ERROR", INT2FIX(XML_PARSER_SEVERITY_VALIDITY_ERROR)); rb_define_const(cXMLReader, "SEVERITY_WARNING", INT2FIX(XML_PARSER_SEVERITY_WARNING)); rb_define_const(cXMLReader, "SEVERITY_ERROR", INT2FIX(XML_PARSER_SEVERITY_ERROR)); rb_define_const(cXMLReader, "TYPE_NONE", INT2FIX(XML_READER_TYPE_NONE)); rb_define_const(cXMLReader, "TYPE_ELEMENT", INT2FIX(XML_READER_TYPE_ELEMENT)); rb_define_const(cXMLReader, "TYPE_ATTRIBUTE", INT2FIX(XML_READER_TYPE_ATTRIBUTE)); rb_define_const(cXMLReader, "TYPE_TEXT", INT2FIX(XML_READER_TYPE_TEXT)); rb_define_const(cXMLReader, "TYPE_CDATA", INT2FIX(XML_READER_TYPE_CDATA)); rb_define_const(cXMLReader, "TYPE_ENTITY_REFERENCE", INT2FIX(XML_READER_TYPE_ENTITY_REFERENCE)); rb_define_const(cXMLReader, "TYPE_ENTITY", INT2FIX(XML_READER_TYPE_ENTITY)); rb_define_const(cXMLReader, "TYPE_PROCESSING_INSTRUCTION", INT2FIX(XML_READER_TYPE_PROCESSING_INSTRUCTION)); rb_define_const(cXMLReader, "TYPE_COMMENT", INT2FIX(XML_READER_TYPE_COMMENT)); rb_define_const(cXMLReader, "TYPE_DOCUMENT", INT2FIX(XML_READER_TYPE_DOCUMENT)); rb_define_const(cXMLReader, "TYPE_DOCUMENT_TYPE", INT2FIX(XML_READER_TYPE_DOCUMENT_TYPE)); rb_define_const(cXMLReader, "TYPE_DOCUMENT_FRAGMENT", INT2FIX(XML_READER_TYPE_DOCUMENT_FRAGMENT)); rb_define_const(cXMLReader, "TYPE_NOTATION", INT2FIX(XML_READER_TYPE_NOTATION)); rb_define_const(cXMLReader, "TYPE_WHITESPACE", INT2FIX(XML_READER_TYPE_WHITESPACE)); rb_define_const(cXMLReader, "TYPE_SIGNIFICANT_WHITESPACE", INT2FIX(XML_READER_TYPE_SIGNIFICANT_WHITESPACE)); rb_define_const(cXMLReader, "TYPE_END_ELEMENT", INT2FIX(XML_READER_TYPE_END_ELEMENT)); rb_define_const(cXMLReader, "TYPE_END_ENTITY", INT2FIX(XML_READER_TYPE_END_ENTITY)); rb_define_const(cXMLReader, "TYPE_XML_DECLARATION", INT2FIX(XML_READER_TYPE_XML_DECLARATION)); /* Read states */ rb_define_const(cXMLReader, "MODE_INITIAL", INT2FIX(XML_TEXTREADER_MODE_INITIAL)); rb_define_const(cXMLReader, "MODE_INTERACTIVE", INT2FIX(XML_TEXTREADER_MODE_INTERACTIVE)); rb_define_const(cXMLReader, "MODE_ERROR", INT2FIX(XML_TEXTREADER_MODE_ERROR)); rb_define_const(cXMLReader, "MODE_EOF", INT2FIX(XML_TEXTREADER_MODE_EOF)); rb_define_const(cXMLReader, "MODE_CLOSED", INT2FIX(XML_TEXTREADER_MODE_CLOSED)); rb_define_const(cXMLReader, "MODE_READING", INT2FIX(XML_TEXTREADER_MODE_READING)); rb_undef_method(CLASS_OF(cXMLReader), "new"); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_input_cbg.c0000644000004100000410000001054714620142101022141 0ustar www-datawww-data/* Author: Martin Povolny (xpovolny@fi.muni.cz) */ #include "ruby_libxml.h" #include "ruby_xml_input_cbg.h" /* Document-class: LibXML::XML::InputCallbacks * * Support for adding custom scheme handlers. */ static ic_scheme *first_scheme = 0; int ic_match(char const *filename) { ic_scheme *scheme; //fprintf( stderr, "ic_match: %s\n", filename ); scheme = first_scheme; while (0 != scheme) { if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST scheme->scheme_name, scheme->name_len)) { return 1; } scheme = scheme->next_scheme; } return 0; } void* ic_open(char const *filename) { ic_doc_context *ic_doc; ic_scheme *scheme; VALUE res; scheme = first_scheme; while (0 != scheme) { if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST scheme->scheme_name, scheme->name_len)) { ic_doc = (ic_doc_context*) malloc(sizeof(ic_doc_context)); res = rb_funcall(scheme->class, rb_intern("document_query"), 1, rb_str_new2(filename)); ic_doc->buffer = strdup(StringValuePtr(res)); ic_doc->bpos = ic_doc->buffer; ic_doc->remaining = (int)strlen(ic_doc->buffer); return ic_doc; } scheme = scheme->next_scheme; } return 0; } int ic_read(void *context, char *buffer, int len) { ic_doc_context *ic_doc; int ret_len; ic_doc = (ic_doc_context*) context; if (len >= ic_doc->remaining) { ret_len = ic_doc->remaining; } else { ret_len = len; } ic_doc->remaining -= ret_len; strncpy(buffer, ic_doc->bpos, ret_len); ic_doc->bpos += ret_len; return ret_len; } int ic_close(void *context) { ruby_xfree(((ic_doc_context*) context)->buffer); ruby_xfree(context); return 1; } /* * call-seq: * register * * Register a new set of I/O callback for handling parser input. */ static VALUE input_callbacks_register_input_callbacks(VALUE self) { xmlRegisterInputCallbacks(ic_match, ic_open, ic_read, ic_close); return (Qtrue); } /* * call-seq: * add_scheme * * No documentation available. */ static VALUE input_callbacks_add_scheme(VALUE self, VALUE scheme_name, VALUE class) { ic_scheme *scheme; Check_Type(scheme_name, T_STRING); scheme = (ic_scheme*) malloc(sizeof(ic_scheme)); scheme->next_scheme = 0; scheme->scheme_name = strdup(StringValuePtr(scheme_name)); /* TODO alloc, dealloc */ scheme->name_len = (int)strlen(scheme->scheme_name); scheme->class = class; /* TODO alloc, dealloc */ //fprintf( stderr, "registered: %s, %d, %s\n", scheme->scheme_name, scheme->name_len, scheme->class ); if (0 == first_scheme) first_scheme = scheme; else { ic_scheme *pos; pos = first_scheme; while (0 != pos->next_scheme) pos = pos->next_scheme; pos->next_scheme = scheme; } return (Qtrue); } /* * call-seq: * remove_scheme * * No documentation available. */ static VALUE input_callbacks_remove_scheme(VALUE self, VALUE scheme_name) { char *name; ic_scheme *save_scheme, *scheme; Check_Type(scheme_name, T_STRING); name = StringValuePtr(scheme_name); if (0 == first_scheme) return Qfalse; if (!strncmp(name, first_scheme->scheme_name, first_scheme->name_len)) { save_scheme = first_scheme->next_scheme; ruby_xfree(first_scheme->scheme_name); ruby_xfree(first_scheme); first_scheme = save_scheme; return Qtrue; } scheme = first_scheme; while (0 != scheme->next_scheme) { if (!strncmp(name, scheme->next_scheme->scheme_name, scheme->next_scheme->name_len)) { save_scheme = scheme->next_scheme->next_scheme; ruby_xfree(scheme->next_scheme->scheme_name); ruby_xfree(scheme->next_scheme); scheme->next_scheme = save_scheme; return Qtrue; } scheme = scheme->next_scheme; } return Qfalse; } void rxml_init_input_callbacks(void) { VALUE cInputCallbacks; cInputCallbacks = rb_define_class_under(mXML, "InputCallbacks", rb_cObject); /* Class Methods */ rb_define_singleton_method(cInputCallbacks, "register", input_callbacks_register_input_callbacks, 0); rb_define_singleton_method(cInputCallbacks, "add_scheme", input_callbacks_add_scheme, 2); rb_define_singleton_method(cInputCallbacks, "remove_scheme", input_callbacks_remove_scheme, 1); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_node.c0000644000004100000410000010567114620142101021117 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_node.h" #include #include #include #include VALUE cXMLNode; /* Document-class: LibXML::XML::Node * * Nodes are the primary objects that make up an XML document. * The node class represents most node types that are found in * an XML document (but not LibXML::XML::Attributes, see LibXML::XML::Attr). * It exposes libxml's full API for creating, querying * moving and deleting node objects. Many of these methods are * documented in the DOM Level 3 specification found at: * http://www.w3.org/TR/DOM-Level-3-Core/. */ /* Memory management: * * The bindings create a one-to-one mapping between ruby objects and * libxml documents and libxml parent nodes (ie, nodes that do not * have a parent and do not belong to a document). In these cases, * the bindings manage the memory. They do this by installing a free * function and storing a back pointer to the Ruby object from the xmlnode * using the _private member on libxml structures. When the Ruby object * goes out of scope, the underlying libxml structure is freed. Libxml * itself then frees all child node (recursively). * * For all other nodes (the vast majority), the bindings create temporary * Ruby objects that get freed once they go out of scope. Thus there can be * more than one ruby object pointing to the same xml node. To mostly hide * this from programmers on the ruby side, the #eql? and #== methods are * overriden to check if two ruby objects wrap the same xmlnode. If they do, * then the methods return true. During the mark phase, each of these temporary * objects marks its owning document, thereby keeping the Ruby document object * alive and thus the xmldoc tree. * * In the sweep phase of the garbage collector, or when a program ends, * there is no order to how Ruby objects are freed. In fact, the ruby document * object is almost always freed before any ruby objects that wrap child nodes. * However, this is ok because those ruby objects do not have a free function * and are no longer in scope (since if they were the document would not be freed). */ static void rxml_node_free(xmlNodePtr xnode) { /* The ruby object wrapping the xml object no longer exists and this is a standalone node without a document or parent so ruby is responsible for freeing the underlying node.*/ if (xnode->doc == NULL && xnode->parent == NULL) { // Remove the back linkage from libxml to Ruby xnode->_private = NULL; xmlFreeNode(xnode); } } void rxml_node_manage(xmlNodePtr xnode, VALUE node) { RDATA(node)->dfree = (RUBY_DATA_FUNC)rxml_node_free; xnode->_private = (void*)node; } void rxml_node_unmanage(xmlNodePtr xnode, VALUE node) { RDATA(node)->dfree = NULL; xnode->_private = NULL; } xmlNodePtr rxml_node_root(xmlNodePtr xnode) { xmlNodePtr current = xnode; while (current->parent) { current = current->parent; } return current; } void rxml_node_mark(xmlNodePtr xnode) { if (xnode->doc) { if (xnode->doc->_private) { VALUE doc = (VALUE)xnode->doc->_private; rb_gc_mark(doc); } } else if (xnode->parent) { xmlNodePtr root = rxml_node_root(xnode); if (root->_private) { VALUE node = (VALUE)root->_private; rb_gc_mark(node); } } } VALUE rxml_node_wrap(xmlNodePtr xnode) { VALUE result = Qnil; // Is this node already wrapped? if (xnode->_private) { result = (VALUE)xnode->_private; } else { result = Data_Wrap_Struct(cXMLNode, rxml_node_mark, NULL, xnode); } if (!xnode->doc && !xnode->parent) { rxml_node_manage(xnode, result); } return result; } static VALUE rxml_node_alloc(VALUE klass) { // This node was created from Ruby so we are responsible for freeing it not libxml return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node_free, NULL); } static xmlNodePtr rxml_get_xnode(VALUE node) { xmlNodePtr result; Data_Get_Struct(node, xmlNode, result); if (!result) rb_raise(rb_eRuntimeError, "This node has already been freed."); return result; } /* * call-seq: * XML::Node.new_cdata(content = nil) -> XML::Node * * Create a new #CDATA node, optionally setting * the node's content. */ static VALUE rxml_node_new_cdata(int argc, VALUE *argv, VALUE klass) { VALUE content = Qnil; xmlNodePtr xnode; rb_scan_args(argc, argv, "01", &content); if (NIL_P(content)) { xnode = xmlNewCDataBlock(NULL, NULL, 0); } else { content = rb_obj_as_string(content); xnode = xmlNewCDataBlock(NULL, (xmlChar*) StringValuePtr(content), (int)RSTRING_LEN(content)); } if (xnode == NULL) rxml_raise(xmlGetLastError()); return rxml_node_wrap(xnode); } /* * call-seq: * XML::Node.new_comment(content = nil) -> XML::Node * * Create a new comment node, optionally setting * the node's content. * */ static VALUE rxml_node_new_comment(int argc, VALUE *argv, VALUE klass) { VALUE content = Qnil; xmlNodePtr xnode; rb_scan_args(argc, argv, "01", &content); if (NIL_P(content)) { xnode = xmlNewComment(NULL); } else { content = rb_obj_as_string(content); xnode = xmlNewComment((xmlChar*) StringValueCStr(content)); } if (xnode == NULL) rxml_raise(xmlGetLastError()); return rxml_node_wrap(xnode); } /* * call-seq: * XML::Node.new_pi(name, content = nil) -> XML::Node * * Create a new pi node, optionally setting * the node's content. * */ static VALUE rxml_node_new_pi(int argc, VALUE *argv, VALUE klass) { VALUE name = Qnil; VALUE content = Qnil; xmlNodePtr xnode; rb_scan_args(argc, argv, "11", &name, &content); if (NIL_P(name)) { rb_raise(rb_eRuntimeError, "You must provide me with a name for a PI."); } name = rb_obj_as_string(name); if (NIL_P(content)) { xnode = xmlNewPI((xmlChar*) StringValuePtr(name), NULL); } else { content = rb_obj_as_string(content); xnode = xmlNewPI((xmlChar*) StringValuePtr(name), (xmlChar*) StringValueCStr(content)); } if (xnode == NULL) rxml_raise(xmlGetLastError()); return rxml_node_wrap(xnode); } /* * call-seq: * XML::Node.new_text(content) -> XML::Node * * Create a new text node. * */ static VALUE rxml_node_new_text(VALUE klass, VALUE content) { xmlNodePtr xnode; Check_Type(content, T_STRING); content = rb_obj_as_string(content); xnode = xmlNewText((xmlChar*) StringValueCStr(content)); if (xnode == NULL) rxml_raise(xmlGetLastError()); return rxml_node_wrap(xnode); } static VALUE rxml_node_content_set(VALUE self, VALUE content); /* * call-seq: * XML::Node.initialize(name, content = nil, namespace = nil) -> XML::Node * * Creates a new element with the specified name, content and * namespace. The content and namespace may be nil. */ static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self) { VALUE name; VALUE content; VALUE ns; xmlNodePtr xnode = NULL; xmlNsPtr xns = NULL; rb_scan_args(argc, argv, "12", &name, &content, &ns); name = rb_obj_as_string(name); if (!NIL_P(ns)) Data_Get_Struct(ns, xmlNs, xns); xnode = xmlNewNode(xns, (xmlChar*) StringValuePtr(name)); if (xnode == NULL) rxml_raise(xmlGetLastError()); // Link the ruby wrapper to the underlying libxml node RDATA(self)->data = xnode; // Ruby is in charge of managing this node's memory rxml_node_manage(xnode, self); if (!NIL_P(content)) rxml_node_content_set(self, content); return self; } static VALUE rxml_node_modify_dom(VALUE self, VALUE target, xmlNodePtr (*xmlFunc)(xmlNodePtr, xmlNodePtr)) { xmlNodePtr xnode, xtarget, xresult; if (rb_obj_is_kind_of(target, cXMLNode) == Qfalse) rb_raise(rb_eTypeError, "Must pass an XML::Node object"); xnode = rxml_get_xnode(self); xtarget = rxml_get_xnode(target); if (xtarget->doc != NULL && xtarget->doc != xnode->doc) rb_raise(eXMLError, "Nodes belong to different documents. You must first import the node by calling LibXML::XML::Document.import"); xmlUnlinkNode(xtarget); // Target is about to have a parent, so stop having ruby manage it. rxml_node_unmanage(xtarget, target); // This target node could be freed here and be replaced by a different node xresult = xmlFunc(xnode, xtarget); if (!xresult) rxml_raise(xmlGetLastError()); /* Assume the target was freed, we need to fix up the ruby object to point to the newly returned node. */ RDATA(target)->data = xresult; return target; } /* * call-seq: * node.base_uri -> "uri" * * Obtain this node's base URI. */ static VALUE rxml_node_base_uri_get(VALUE self) { xmlNodePtr xnode; xmlChar* base_uri; VALUE result = Qnil; xnode = rxml_get_xnode(self); if (xnode->doc == NULL) return (result); base_uri = xmlNodeGetBase(xnode->doc, xnode); if (base_uri) { result = rxml_new_cstr( base_uri, NULL); xmlFree(base_uri); } return (result); } // TODO node_base_set should support setting back to nil /* * call-seq: * node.base_uri = "uri" * * Set this node's base URI. */ static VALUE rxml_node_base_uri_set(VALUE self, VALUE uri) { xmlNodePtr xnode; Check_Type(uri, T_STRING); xnode = rxml_get_xnode(self); if (xnode->doc == NULL) return (Qnil); xmlNodeSetBase(xnode, (xmlChar*) StringValuePtr(uri)); return (Qtrue); } /* * call-seq: * node.content -> "string" * * Obtain this node's content as a string. */ static VALUE rxml_node_content_get(VALUE self) { xmlNodePtr xnode; xmlChar *content; VALUE result = Qnil; xnode = rxml_get_xnode(self); content = xmlNodeGetContent(xnode); if (content) { result = rxml_new_cstr(content, NULL); xmlFree(content); } return result; } /* * call-seq: * node.content = "string" * * Set this node's content to the specified string. */ static VALUE rxml_node_content_set(VALUE self, VALUE content) { xmlNodePtr xnode; xmlChar* encoded_content; Check_Type(content, T_STRING); xnode = rxml_get_xnode(self); encoded_content = xmlEncodeSpecialChars(xnode->doc, (xmlChar*) StringValuePtr(content)); xmlNodeSetContent(xnode, encoded_content); xmlFree(encoded_content); return (Qtrue); } /* * call-seq: * node.debug -> true|false * * Print libxml debugging information to stdout. * Requires that libxml was compiled with debugging enabled. */ static VALUE rxml_node_debug(VALUE self) { #ifdef LIBXML_DEBUG_ENABLED xmlNodePtr xnode; xnode = rxml_get_xnode(self); xmlDebugDumpNode(NULL, xnode, 2); return Qtrue; #else rb_warn("libxml was compiled without debugging support."); return Qfalse; #endif } /* * call-seq: * node.first -> XML::Node * * Returns this node's first child node if any. */ static VALUE rxml_node_first_get(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); if (xnode->children) return (rxml_node_wrap(xnode->children)); else return (Qnil); } /* * call-seq: * curr_node << "Some text" * curr_node << node * * Add the specified text or XML::Node as a new child node to the * current node. * * If the specified argument is a string, it should be a raw string * that contains unescaped XML special characters. Entity references * are not supported. * * The method will return the current node. */ static VALUE rxml_node_content_add(VALUE self, VALUE obj) { xmlNodePtr xnode; VALUE str; xnode = rxml_get_xnode(self); /* XXX This should only be legal for a CDATA type node, I think, * resulting in a merge of content, as if a string were passed * danj 070827 */ if (rb_obj_is_kind_of(obj, cXMLNode)) { rxml_node_modify_dom(self, obj, xmlAddChild); } else { str = rb_obj_as_string(obj); if (NIL_P(str) || TYPE(str) != T_STRING) rb_raise(rb_eTypeError, "invalid argument: must be string or XML::Node"); xmlNodeAddContent(xnode, (xmlChar*) StringValuePtr(str)); } return self; } /* * call-seq: * node.doc -> document * * Obtain the XML::Document this node belongs to. */ static VALUE rxml_node_doc(VALUE self) { xmlDocPtr xdoc = NULL; xmlNodePtr xnode = rxml_get_xnode(self); switch (xnode->type) { case XML_DOCUMENT_NODE: #ifdef LIBXML_DOCB_ENABLED case XML_DOCB_DOCUMENT_NODE: #endif case XML_HTML_DOCUMENT_NODE: case XML_NAMESPACE_DECL: break; case XML_ATTRIBUTE_NODE: xdoc = (xmlDocPtr)((xmlAttrPtr) xnode->doc); break; default: xdoc = xnode->doc; } if (xdoc == NULL) return (Qnil); return (VALUE)xdoc->_private; } /* * call-seq: * node.to_s -> "string" * node.to_s(:indent => true, :encoding => 'UTF-8', :level => 0) -> "string" * * Converts a node, and all of its children, to a string representation. * To include only the node's children, use the the XML::Node#inner_xml * method. * * You may provide an optional hash table to control how the string is * generated. Valid options are: * * :indent - Specifies if the string should be indented. The default value * is true. Note that indentation is only added if both :indent is * true and XML.indent_tree_output is true. If :indent is set to false, * then both indentation and line feeds are removed from the result. * * :level - Specifies the indentation level. The amount of indentation * is equal to the (level * number_spaces) + number_spaces, where libxml * defaults the number of spaces to 2. Thus a level of 0 results in * 2 spaces, level 1 results in 4 spaces, level 2 results in 6 spaces, etc. * * :encoding - Specifies the output encoding of the string. It * defaults to XML::Encoding::UTF8. To change it, use one of the * XML::Encoding encoding constants. */ static VALUE rxml_node_to_s(int argc, VALUE *argv, VALUE self) { VALUE result = Qnil; VALUE options = Qnil; xmlNodePtr xnode; xmlCharEncodingHandlerPtr encodingHandler; xmlOutputBufferPtr output; int level = 0; int indent = 1; const xmlChar *xencoding = (const xmlChar*)"UTF-8"; rb_scan_args(argc, argv, "01", &options); if (!NIL_P(options)) { VALUE rencoding, rindent, rlevel; Check_Type(options, T_HASH); rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding"))); rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent"))); rlevel = rb_hash_aref(options, ID2SYM(rb_intern("level"))); if (rindent == Qfalse) indent = 0; if (rlevel != Qnil) level = NUM2INT(rlevel); if (rencoding != Qnil) { xencoding = (const xmlChar*)xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding)); if (!xencoding) rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding)); } } encodingHandler = xmlFindCharEncodingHandler((const char*)xencoding); output = xmlAllocOutputBuffer(encodingHandler); xnode = rxml_get_xnode(self); xmlNodeDumpOutput(output, xnode->doc, xnode, level, indent, (const char*)xencoding); xmlOutputBufferFlush(output); #ifdef LIBXML2_NEW_BUFFER if (output->conv) result = rxml_new_cstr(xmlBufContent(output->conv), xencoding); else result = rxml_new_cstr(xmlBufContent(output->buffer), xencoding); #else if (output->conv) result = rxml_new_cstr(xmlBufferContent(output->conv), xencoding); else result = rxml_new_cstr(xmlBufferContent(output->buffer), xencoding); #endif xmlOutputBufferClose(output); return result; } /* * call-seq: * node.each -> XML::Node * * Iterates over this node's children, including text * nodes, element nodes, etc. If you wish to iterate * only over child elements, use XML::Node#each_element. * * doc = XML::Document.new('model/books.xml') * doc.root.each {|node| puts node} */ static VALUE rxml_node_each(VALUE self) { xmlNodePtr xnode; xmlNodePtr xcurrent; xnode = rxml_get_xnode(self); xcurrent = xnode->children; while (xcurrent) { /* The user could remove this node, so first stache away the next node. */ xmlNodePtr xnext = xcurrent->next; rb_yield(rxml_node_wrap(xcurrent)); xcurrent = xnext; } return Qnil; } /* * call-seq: * node.empty? -> (true|false) * * Determine whether this node is an empty or whitespace only text-node. */ static VALUE rxml_node_empty_q(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); if (xnode == NULL) return (Qnil); return ((xmlIsBlankNode(xnode) == 1) ? Qtrue : Qfalse); } /* * call-seq: * node.eql?(other_node) => (true|false) * * Test equality between the two nodes. Two nodes are equal * if they are the same node.*/ static VALUE rxml_node_eql_q(VALUE self, VALUE other) { if (self == other) { return Qtrue; } else if (NIL_P(other)) { return Qfalse; } else { xmlNodePtr xnode = rxml_get_xnode(self); xmlNodePtr xnode_other = rxml_get_xnode(other); return xnode == xnode_other ? Qtrue : Qfalse; } } /* * call-seq: * node.lang -> "string" * * Obtain the language set for this node, if any. * This is set in XML via the xml:lang attribute. */ static VALUE rxml_node_lang_get(VALUE self) { xmlNodePtr xnode; xmlChar *lang; VALUE result = Qnil; xnode = rxml_get_xnode(self); lang = xmlNodeGetLang(xnode); if (lang) { result = rxml_new_cstr( lang, NULL); xmlFree(lang); } return (result); } // TODO node_lang_set should support setting back to nil /* * call-seq: * node.lang = "string" * * Set the language for this node. This affects the value * of the xml:lang attribute. */ static VALUE rxml_node_lang_set(VALUE self, VALUE lang) { xmlNodePtr xnode; Check_Type(lang, T_STRING); xnode = rxml_get_xnode(self); xmlNodeSetLang(xnode, (xmlChar*) StringValuePtr(lang)); return (Qtrue); } /* * call-seq: * node.last -> XML::Node * * Obtain the last child node of this node, if any. */ static VALUE rxml_node_last_get(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); if (xnode->last) return (rxml_node_wrap(xnode->last)); else return (Qnil); } /* * call-seq: * node.line_num -> num * * Obtain the line number (in the XML document) that this * node was read from. If +default_line_numbers+ is set * false (the default), this method returns zero. */ static VALUE rxml_node_line_num(VALUE self) { xmlNodePtr xnode; long line_num; xnode = rxml_get_xnode(self); line_num = xmlGetLineNo(xnode); if (line_num == -1) return (Qnil); else return (LONG2NUM((long) line_num)); } /* * call-seq: * node.xlink? -> (true|false) * * Determine whether this node is an xlink node. */ static VALUE rxml_node_xlink_q(VALUE self) { xmlNodePtr xnode; xlinkType xlt; xnode = rxml_get_xnode(self); xlt = xlinkIsLink(xnode->doc, xnode); if (xlt == XLINK_TYPE_NONE) return (Qfalse); else return (Qtrue); } /* * call-seq: * node.xlink_type -> num * * Obtain the type identifier for this xlink, if applicable. * If this is not an xlink node (see +xlink?+), will return * nil. */ static VALUE rxml_node_xlink_type(VALUE self) { xmlNodePtr xnode; xlinkType xlt; xnode = rxml_get_xnode(self); xlt = xlinkIsLink(xnode->doc, xnode); if (xlt == XLINK_TYPE_NONE) return (Qnil); else return (INT2NUM(xlt)); } /* * call-seq: * node.xlink_type_name -> "string" * * Obtain the type name for this xlink, if applicable. * If this is not an xlink node (see +xlink?+), will return * nil. */ static VALUE rxml_node_xlink_type_name(VALUE self) { xmlNodePtr xnode; xlinkType xlt; xnode = rxml_get_xnode(self); xlt = xlinkIsLink(xnode->doc, xnode); switch (xlt) { case XLINK_TYPE_NONE: return (Qnil); case XLINK_TYPE_SIMPLE: return (rxml_new_cstr((const xmlChar*)"simple", NULL)); case XLINK_TYPE_EXTENDED: return (rxml_new_cstr((const xmlChar*)"extended", NULL)); case XLINK_TYPE_EXTENDED_SET: return (rxml_new_cstr((const xmlChar*)"extended_set", NULL)); default: rb_fatal("Unknowng xlink type, %d", xlt); } } /* * call-seq: * node.name -> "string" * * Obtain this node's name. */ static VALUE rxml_node_name_get(VALUE self) { xmlNodePtr xnode; const xmlChar *name; xnode = rxml_get_xnode(self); switch (xnode->type) { case XML_DOCUMENT_NODE: #ifdef LIBXML_DOCB_ENABLED case XML_DOCB_DOCUMENT_NODE: #endif case XML_HTML_DOCUMENT_NODE: { xmlDocPtr doc = (xmlDocPtr) xnode; name = doc->URL; break; } case XML_ATTRIBUTE_NODE: { xmlAttrPtr attr = (xmlAttrPtr) xnode; name = attr->name; break; } case XML_NAMESPACE_DECL: { xmlNsPtr ns = (xmlNsPtr) xnode; name = ns->prefix; break; } default: name = xnode->name; break; } if (xnode->name == NULL) return (Qnil); else return (rxml_new_cstr( name, NULL)); } /* * call-seq: * node.name = "string" * * Set this node's name. */ static VALUE rxml_node_name_set(VALUE self, VALUE name) { xmlNodePtr xnode; const xmlChar *xname; Check_Type(name, T_STRING); xnode = rxml_get_xnode(self); xname = (const xmlChar*)StringValuePtr(name); /* Note: calling xmlNodeSetName() for a text node is ignored by libXML. */ xmlNodeSetName(xnode, xname); return (Qtrue); } /* * call-seq: * node.next -> XML::Node * * Returns the next sibling node if one exists. */ static VALUE rxml_node_next_get(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); if (xnode->next) return (rxml_node_wrap(xnode->next)); else return (Qnil); } /* * call-seq: * curr_node.next = node * * Adds the specified node as the next sibling of the current node. * If the node already exists in the document, it is first removed * from its existing context. Any adjacent text nodes will be * merged together, meaning the returned node may be different * than the original node. */ static VALUE rxml_node_next_set(VALUE self, VALUE next) { return rxml_node_modify_dom(self, next, xmlAddNextSibling); } /* * call-seq: * node.parent -> XML::Node * * Obtain this node's parent node, if any. */ static VALUE rxml_node_parent_get(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); if (xnode->parent) return (rxml_node_wrap(xnode->parent)); else return (Qnil); } /* * call-seq: * node.path -> path * * Obtain this node's path. */ static VALUE rxml_node_path(VALUE self) { xmlNodePtr xnode; xmlChar *path; VALUE result = Qnil; xnode = rxml_get_xnode(self); path = xmlGetNodePath(xnode); if (path) { result = rxml_new_cstr( path, NULL); xmlFree(path); } return result; } /* * call-seq: * node.prev -> XML::Node * * Obtain the previous sibling, if any. */ static VALUE rxml_node_prev_get(VALUE self) { xmlNodePtr xnode; xmlNodePtr node; xnode = rxml_get_xnode(self); switch (xnode->type) { case XML_DOCUMENT_NODE: #ifdef LIBXML_DOCB_ENABLED case XML_DOCB_DOCUMENT_NODE: #endif case XML_HTML_DOCUMENT_NODE: case XML_NAMESPACE_DECL: node = NULL; break; case XML_ATTRIBUTE_NODE: { xmlAttrPtr attr = (xmlAttrPtr) xnode; node = (xmlNodePtr) attr->prev; } break; default: node = xnode->prev; break; } if (node == NULL) return (Qnil); else return (rxml_node_wrap(node)); } /* * call-seq: * curr_node.prev = node * * Adds the specified node as the previous sibling of the current node. * If the node already exists in the document, it is first removed * from its existing context. Any adjacent text nodes will be * merged together, meaning the returned node may be different * than the original node. */ static VALUE rxml_node_prev_set(VALUE self, VALUE prev) { return rxml_node_modify_dom(self, prev, xmlAddPrevSibling); } /* * call-seq: * node.attributes -> attributes * * Returns the XML::Attributes for this node. */ static VALUE rxml_node_attributes_get(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); return rxml_attributes_new(xnode); } /* * call-seq: * node.property("name") -> "string" * node["name"] -> "string" * * Obtain the named property. */ static VALUE rxml_node_attribute_get(VALUE self, VALUE name) { VALUE attributes = rxml_node_attributes_get(self); return rxml_attributes_attribute_get(attributes, name); } /* * call-seq: * node["name"] = "string" * * Set the named property. */ static VALUE rxml_node_property_set(VALUE self, VALUE name, VALUE value) { VALUE attributes = rxml_node_attributes_get(self); return rxml_attributes_attribute_set(attributes, name, value); } /* * call-seq: * node.remove! -> node * * Removes this node and its children from the document tree by setting its document, * parent and siblings to nil. You can add the returned node back into a document. * Otherwise, the node will be freed once any references to it go out of scope. */ static VALUE rxml_node_remove_ex(VALUE self) { xmlNodePtr xnode = rxml_get_xnode(self); // Now unlink the node from its parent xmlUnlinkNode(xnode); // Ruby now manages this node rxml_node_manage(xnode, self); // Now return the removed node so the user can do something with it return self; } /* * call-seq: * curr_node.sibling = node * * Adds the specified node as the end of the current node's list * of siblings. If the node already exists in the document, it * is first removed from its existing context. Any adjacent text * nodes will be merged together, meaning the returned node may * be different than the original node. */ static VALUE rxml_node_sibling_set(VALUE self, VALUE sibling) { return rxml_node_modify_dom(self, sibling, xmlAddSibling); } /* * call-seq: * text_node.output_escaping? -> (true|false) * element_node.output_escaping? -> (true|false|nil) * attribute_node.output_escaping? -> (true|false|nil) * other_node.output_escaping? -> (nil) * * Determine whether this node escapes it's output or not. * * Text nodes return only +true+ or +false+. Element and attribute nodes * examine their immediate text node children to determine the value. * Any other type of node always returns +nil+. * * If an element or attribute node has at least one immediate child text node * and all the immediate text node children have the same +output_escaping?+ * value, that value is returned. Otherwise, +nil+ is returned. */ static VALUE rxml_node_output_escaping_q(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); switch (xnode->type) { case XML_TEXT_NODE: return xnode->name==xmlStringTextNoenc ? Qfalse : Qtrue; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: { xmlNodePtr tmp = xnode->children; const xmlChar *match = NULL; /* Find the first text node and use it as the reference. */ while (tmp && tmp->type != XML_TEXT_NODE) tmp = tmp->next; if (! tmp) return Qnil; match = tmp->name; /* Walk the remaining text nodes until we run out or one doesn't match. */ while (tmp && (tmp->type != XML_TEXT_NODE || match == tmp->name)) tmp = tmp->next; /* We're left with either the mismatched node or the aggregate result. */ return tmp ? Qnil : (match==xmlStringTextNoenc ? Qfalse : Qtrue); } break; default: return Qnil; } } /* * call-seq: * text_node.output_escaping = true|false * element_node.output_escaping = true|false * attribute_node.output_escaping = true|false * * Controls whether this text node or the immediate text node children of an * element or attribute node escapes their output. Any other type of node * will simply ignore this operation. * * Text nodes which are added to an element or attribute node will be affected * by any previous setting of this property. */ static VALUE rxml_node_output_escaping_set(VALUE self, VALUE value) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); switch (xnode->type) { case XML_TEXT_NODE: xnode->name = (value != Qfalse && value != Qnil) ? xmlStringText : xmlStringTextNoenc; break; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: { const xmlChar *name = (value != Qfalse && value != Qnil) ? xmlStringText : xmlStringTextNoenc; xmlNodePtr tmp; for (tmp = xnode->children; tmp; tmp = tmp->next) if (tmp->type == XML_TEXT_NODE) tmp->name = name; } break; default: return Qnil; } return (value!=Qfalse && value!=Qnil) ? Qtrue : Qfalse; } /* * call-seq: * node.space_preserve -> (true|false) * * Determine whether this node preserves whitespace. */ static VALUE rxml_node_space_preserve_get(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); return (INT2NUM(xmlNodeGetSpacePreserve(xnode))); } /* * call-seq: * node.space_preserve = true|false * * Control whether this node preserves whitespace. */ static VALUE rxml_node_space_preserve_set(VALUE self, VALUE value) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); if (value == Qfalse) xmlNodeSetSpacePreserve(xnode, 0); else xmlNodeSetSpacePreserve(xnode, 1); return (Qnil); } /* * call-seq: * node.type -> num * * Obtain this node's type identifier. */ static VALUE rxml_node_type(VALUE self) { xmlNodePtr xnode; xnode = rxml_get_xnode(self); return (INT2NUM(xnode->type)); } /* * call-seq: * node.copy -> XML::Node * * Creates a copy of this node. To create a * shallow copy set the deep parameter to false. * To create a deep copy set the deep parameter * to true. * */ static VALUE rxml_node_copy(VALUE self, VALUE deep) { xmlNodePtr xnode; xmlNodePtr xcopy; int recursive = (deep == Qnil || deep == Qfalse) ? 0 : 1; xnode = rxml_get_xnode(self); xcopy = xmlCopyNode(xnode, recursive); if (xcopy) return rxml_node_wrap(xcopy); else return Qnil; } void rxml_init_node(void) { cXMLNode = rb_define_class_under(mXML, "Node", rb_cObject); rb_define_const(cXMLNode, "SPACE_DEFAULT", INT2NUM(0)); rb_define_const(cXMLNode, "SPACE_PRESERVE", INT2NUM(1)); rb_define_const(cXMLNode, "SPACE_NOT_INHERIT", INT2NUM(-1)); rb_define_const(cXMLNode, "XLINK_ACTUATE_AUTO", INT2NUM(1)); rb_define_const(cXMLNode, "XLINK_ACTUATE_NONE", INT2NUM(0)); rb_define_const(cXMLNode, "XLINK_ACTUATE_ONREQUEST", INT2NUM(2)); rb_define_const(cXMLNode, "XLINK_SHOW_EMBED", INT2NUM(2)); rb_define_const(cXMLNode, "XLINK_SHOW_NEW", INT2NUM(1)); rb_define_const(cXMLNode, "XLINK_SHOW_NONE", INT2NUM(0)); rb_define_const(cXMLNode, "XLINK_SHOW_REPLACE", INT2NUM(3)); rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED", INT2NUM(2)); rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED_SET", INT2NUM(3)); rb_define_const(cXMLNode, "XLINK_TYPE_NONE", INT2NUM(0)); rb_define_const(cXMLNode, "XLINK_TYPE_SIMPLE", INT2NUM(1)); rb_define_const(cXMLNode, "ELEMENT_NODE", INT2FIX(XML_ELEMENT_NODE)); rb_define_const(cXMLNode, "ATTRIBUTE_NODE", INT2FIX(XML_ATTRIBUTE_NODE)); rb_define_const(cXMLNode, "TEXT_NODE", INT2FIX(XML_TEXT_NODE)); rb_define_const(cXMLNode, "CDATA_SECTION_NODE", INT2FIX(XML_CDATA_SECTION_NODE)); rb_define_const(cXMLNode, "ENTITY_REF_NODE", INT2FIX(XML_ENTITY_REF_NODE)); rb_define_const(cXMLNode, "ENTITY_NODE", INT2FIX(XML_ENTITY_NODE)); rb_define_const(cXMLNode, "PI_NODE", INT2FIX(XML_PI_NODE)); rb_define_const(cXMLNode, "COMMENT_NODE", INT2FIX(XML_COMMENT_NODE)); rb_define_const(cXMLNode, "DOCUMENT_NODE", INT2FIX(XML_DOCUMENT_NODE)); rb_define_const(cXMLNode, "DOCUMENT_TYPE_NODE", INT2FIX(XML_DOCUMENT_TYPE_NODE)); rb_define_const(cXMLNode, "DOCUMENT_FRAG_NODE", INT2FIX(XML_DOCUMENT_FRAG_NODE)); rb_define_const(cXMLNode, "NOTATION_NODE", INT2FIX(XML_NOTATION_NODE)); rb_define_const(cXMLNode, "HTML_DOCUMENT_NODE", INT2FIX(XML_HTML_DOCUMENT_NODE)); rb_define_const(cXMLNode, "DTD_NODE", INT2FIX(XML_DTD_NODE)); rb_define_const(cXMLNode, "ELEMENT_DECL", INT2FIX(XML_ELEMENT_DECL)); rb_define_const(cXMLNode, "ATTRIBUTE_DECL", INT2FIX(XML_ATTRIBUTE_DECL)); rb_define_const(cXMLNode, "ENTITY_DECL", INT2FIX(XML_ENTITY_DECL)); rb_define_const(cXMLNode, "NAMESPACE_DECL", INT2FIX(XML_NAMESPACE_DECL)); rb_define_const(cXMLNode, "XINCLUDE_START", INT2FIX(XML_XINCLUDE_START)); rb_define_const(cXMLNode, "XINCLUDE_END", INT2FIX(XML_XINCLUDE_END)); #ifdef LIBXML_DOCB_ENABLED rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", INT2FIX(XML_DOCB_DOCUMENT_NODE)); #else rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", Qnil); #endif rb_define_singleton_method(cXMLNode, "new_cdata", rxml_node_new_cdata, -1); rb_define_singleton_method(cXMLNode, "new_comment", rxml_node_new_comment, -1); rb_define_singleton_method(cXMLNode, "new_pi", rxml_node_new_pi, -1); rb_define_singleton_method(cXMLNode, "new_text", rxml_node_new_text, 1); /* Initialization */ rb_define_alloc_func(cXMLNode, rxml_node_alloc); rb_define_method(cXMLNode, "initialize", rxml_node_initialize, -1); /* Traversal */ rb_include_module(cXMLNode, rb_mEnumerable); rb_define_method(cXMLNode, "[]", rxml_node_attribute_get, 1); rb_define_method(cXMLNode, "each", rxml_node_each, 0); rb_define_method(cXMLNode, "first", rxml_node_first_get, 0); rb_define_method(cXMLNode, "last", rxml_node_last_get, 0); rb_define_method(cXMLNode, "next", rxml_node_next_get, 0); rb_define_method(cXMLNode, "parent", rxml_node_parent_get, 0); rb_define_method(cXMLNode, "prev", rxml_node_prev_get, 0); /* Modification */ rb_define_method(cXMLNode, "[]=", rxml_node_property_set, 2); rb_define_method(cXMLNode, "<<", rxml_node_content_add, 1); rb_define_method(cXMLNode, "sibling=", rxml_node_sibling_set, 1); rb_define_method(cXMLNode, "next=", rxml_node_next_set, 1); rb_define_method(cXMLNode, "prev=", rxml_node_prev_set, 1); /* Rest of the node api */ rb_define_method(cXMLNode, "attributes", rxml_node_attributes_get, 0); rb_define_method(cXMLNode, "base_uri", rxml_node_base_uri_get, 0); rb_define_method(cXMLNode, "base_uri=", rxml_node_base_uri_set, 1); rb_define_method(cXMLNode, "blank?", rxml_node_empty_q, 0); rb_define_method(cXMLNode, "copy", rxml_node_copy, 1); rb_define_method(cXMLNode, "content", rxml_node_content_get, 0); rb_define_method(cXMLNode, "content=", rxml_node_content_set, 1); rb_define_method(cXMLNode, "debug", rxml_node_debug, 0); rb_define_method(cXMLNode, "doc", rxml_node_doc, 0); rb_define_method(cXMLNode, "empty?", rxml_node_empty_q, 0); rb_define_method(cXMLNode, "eql?", rxml_node_eql_q, 1); rb_define_method(cXMLNode, "lang", rxml_node_lang_get, 0); rb_define_method(cXMLNode, "lang=", rxml_node_lang_set, 1); rb_define_method(cXMLNode, "line_num", rxml_node_line_num, 0); rb_define_method(cXMLNode, "name", rxml_node_name_get, 0); rb_define_method(cXMLNode, "name=", rxml_node_name_set, 1); rb_define_method(cXMLNode, "node_type", rxml_node_type, 0); rb_define_method(cXMLNode, "output_escaping?", rxml_node_output_escaping_q, 0); rb_define_method(cXMLNode, "output_escaping=", rxml_node_output_escaping_set, 1); rb_define_method(cXMLNode, "path", rxml_node_path, 0); rb_define_method(cXMLNode, "remove!", rxml_node_remove_ex, 0); rb_define_method(cXMLNode, "space_preserve", rxml_node_space_preserve_get, 0); rb_define_method(cXMLNode, "space_preserve=", rxml_node_space_preserve_set, 1); rb_define_method(cXMLNode, "to_s", rxml_node_to_s, -1); rb_define_method(cXMLNode, "xlink?", rxml_node_xlink_q, 0); rb_define_method(cXMLNode, "xlink_type", rxml_node_xlink_type, 0); rb_define_method(cXMLNode, "xlink_type_name", rxml_node_xlink_type_name, 0); rb_define_alias(cXMLNode, "==", "eql?"); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_parser_context.h0000644000004100000410000000034714620142101023231 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_PARSER_CONTEXT__ #define __RXML_PARSER_CONTEXT__ extern VALUE cXMLParserContext; void rxml_init_parser_context(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_parser.h0000644000004100000410000000031014620142101021453 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_PARSER__ #define __RXML_PARSER__ extern VALUE cXMLParser; void rxml_init_parser(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_error.c0000644000004100000410000022276014620142101021322 0ustar www-datawww-data#include "ruby_libxml.h" #include VALUE eXMLError; static ID CALL_METHOD; static ID ERROR_HANDLER_ID; /* * Document-class: LibXML::XML::Error * * The XML::Error class exposes libxml errors as * standard Ruby exceptions. When appropriate, * libxml-ruby will raise an exception - for example, * when parsing a non-well formed xml document. * * By default, warnings, errors and fatal errors that * libxml generates are printed to STDERR via the * XML::Error::VERBOSE_HANDLER proc. * * To disable this output you can install the quiet handler: * * XML::Error.set_handler(&XML::Error::QUIET_HANDLER) * * Get the current handler: * * proc = XML::Error.get_handler * * Install your own handler: * * XML::Error.set_handler do |error| * puts error.to_s * end * * Or remove all handlers: * * XML::Error.reset_handler */ /* * call-seq: * Error.get_error_handler * * Returns the proc that will be called when libxml generates * warning, error or fatal error messages. */ static VALUE rxml_error_get_handler(VALUE self) { VALUE block = rb_cvar_get(eXMLError, ERROR_HANDLER_ID); return block; } VALUE rxml_error_wrap(const xmlError *xerror) { VALUE result = Qnil; if (xerror->message) result = rb_exc_new2(eXMLError, xerror->message); else result = rb_class_new_instance(0, NULL, eXMLError); rb_iv_set(result, "@domain", INT2NUM(xerror->domain)); rb_iv_set(result, "@code", INT2NUM(xerror->code)); rb_iv_set(result, "@level", INT2NUM(xerror->level)); if (xerror->file) rb_iv_set(result, "@file", rb_str_new2(xerror->file)); if (xerror->line) rb_iv_set(result, "@line", INT2NUM(xerror->line)); if (xerror->str1) rb_iv_set(result, "@str1", rb_str_new2(xerror->str1)); if (xerror->str2) rb_iv_set(result, "@str2", rb_str_new2(xerror->str2)); if (xerror->str3) rb_iv_set(result, "@str3", rb_str_new2(xerror->str3)); rb_iv_set(result, "@int1", INT2NUM(xerror->int1)); rb_iv_set(result, "@int2", INT2NUM(xerror->int2)); if (xerror->node) { /* Returning the original node is too dangerous because its parent document is never returned to Ruby. So return a copy of the node, which does not belong to any document, and can free itself when Ruby calls its free method. Note we just copy the node, and don't bother with the overhead of a recursive query. */ xmlNodePtr xNode = xmlCopyNode((const xmlNodePtr)xerror->node, 2); VALUE node = rxml_node_wrap(xNode); rb_iv_set(result, "@node", node); } return result; } /* Hook that receives xml error message */ #if LIBXML_VERSION >= 21200 static void structuredErrorFunc(void *userData, const xmlError *xerror) #else static void structuredErrorFunc(void *userData, xmlErrorPtr xerror) #endif { VALUE error = rxml_error_wrap(xerror); /* Wrap error up as Ruby object and send it off to ruby */ VALUE block = rxml_error_get_handler(error); /* Now call global handler */ if (block != Qnil) { rb_funcall(block, CALL_METHOD, 1, error); } } static void rxml_set_handler(VALUE self, VALUE block) { #ifdef RB_CVAR_SET_4ARGS rb_cvar_set(self, ERROR_HANDLER_ID, block, 0); #else rb_cvar_set(self, ERROR_HANDLER_ID, block); #endif /* Intercept libxml error handlers */ xmlSetStructuredErrorFunc(NULL, structuredErrorFunc); } /* * call-seq: * Error.set_error_handler {|error| ... } * * Registers a block that will be called with an instance of * XML::Error when libxml generates warning, error or fatal * error messages. */ static VALUE rxml_error_set_handler(VALUE self) { VALUE block; if (rb_block_given_p() == Qfalse) rb_raise(rb_eRuntimeError, "No block given"); block = rb_block_proc(); /* Embed the block within the Error class to avoid it to be collected. Previous handler will be overwritten if it exists. */ rxml_set_handler(self, block); return self; } /* * call-seq: * Error.reset_error_handler * * Removes the current error handler. */ static VALUE rxml_error_reset_handler(VALUE self) { rxml_set_handler(self, Qnil); return self; } void rxml_raise(const xmlError *xerror) { if (xerror) { /* Wrap error up as Ruby object and send it off to ruby */ VALUE error = rxml_error_wrap(xerror); rb_exc_raise(error); } } void rxml_init_error(void) { CALL_METHOD = rb_intern("call"); ERROR_HANDLER_ID = rb_intern("@@__error_handler_callback__"); /* Error class */ eXMLError = rb_define_class_under(mXML, "Error", rb_eStandardError); rb_define_singleton_method(eXMLError, "get_handler", rxml_error_get_handler, 0); rb_define_singleton_method(eXMLError, "set_handler", rxml_error_set_handler, 0); rb_define_singleton_method(eXMLError, "reset_handler", rxml_error_reset_handler, 0); /* Ruby callback to receive errors - set it to nil by default. */ rxml_set_handler(eXMLError, Qnil); /* Error attributes */ rb_define_attr(eXMLError, "level", 1, 0); rb_define_attr(eXMLError, "domain", 1, 0); rb_define_attr(eXMLError, "code", 1, 0); rb_define_attr(eXMLError, "file", 1, 0); rb_define_attr(eXMLError, "line", 1, 0); rb_define_attr(eXMLError, "str1", 1, 0); rb_define_attr(eXMLError, "str2", 1, 0); rb_define_attr(eXMLError, "str3", 1, 0); rb_define_attr(eXMLError, "int1", 1, 0); rb_define_attr(eXMLError, "int2", 1, 0); rb_define_attr(eXMLError, "ctxt", 1, 0); rb_define_attr(eXMLError, "node", 1, 0); /* xml error levels */ rb_define_const(eXMLError, "NONE", INT2NUM(XML_ERR_NONE)); rb_define_const(eXMLError, "WARNING", INT2NUM(XML_ERR_WARNING)); rb_define_const(eXMLError, "ERROR", INT2NUM(XML_ERR_ERROR)); rb_define_const(eXMLError, "FATAL", INT2NUM(XML_ERR_FATAL)); /* xml error domains */ rb_define_const(eXMLError, "NO_ERROR", INT2NUM(XML_FROM_NONE)); rb_define_const(eXMLError, "PARSER", INT2NUM(XML_FROM_PARSER)); rb_define_const(eXMLError, "TREE", INT2NUM(XML_FROM_TREE)); rb_define_const(eXMLError, "NAMESPACE", INT2NUM(XML_FROM_NAMESPACE)); rb_define_const(eXMLError, "DTD", INT2NUM(XML_FROM_DTD)); rb_define_const(eXMLError, "HTML", INT2NUM(XML_FROM_HTML)); rb_define_const(eXMLError, "MEMORY", INT2NUM(XML_FROM_MEMORY)); rb_define_const(eXMLError, "OUTPUT", INT2NUM(XML_FROM_OUTPUT)); rb_define_const(eXMLError, "IO", INT2NUM(XML_FROM_IO)); rb_define_const(eXMLError, "FTP", INT2NUM(XML_FROM_FTP)); rb_define_const(eXMLError, "HTTP", INT2NUM(XML_FROM_HTTP)); rb_define_const(eXMLError, "XINCLUDE", INT2NUM(XML_FROM_XINCLUDE)); rb_define_const(eXMLError, "XPATH", INT2NUM(XML_FROM_XPATH)); rb_define_const(eXMLError, "XPOINTER", INT2NUM(XML_FROM_XPOINTER)); rb_define_const(eXMLError, "REGEXP", INT2NUM(XML_FROM_REGEXP)); rb_define_const(eXMLError, "DATATYPE", INT2NUM(XML_FROM_DATATYPE)); rb_define_const(eXMLError, "SCHEMASP", INT2NUM(XML_FROM_SCHEMASP)); rb_define_const(eXMLError, "SCHEMASV", INT2NUM(XML_FROM_SCHEMASV)); rb_define_const(eXMLError, "RELAXNGP", INT2NUM(XML_FROM_RELAXNGP)); rb_define_const(eXMLError, "RELAXNGV", INT2NUM(XML_FROM_RELAXNGV)); rb_define_const(eXMLError, "CATALOG", INT2NUM(XML_FROM_CATALOG)); rb_define_const(eXMLError, "C14N", INT2NUM(XML_FROM_C14N)); rb_define_const(eXMLError, "XSLT", INT2NUM(XML_FROM_XSLT)); rb_define_const(eXMLError, "VALID", INT2NUM(XML_FROM_VALID)); rb_define_const(eXMLError, "CHECK", INT2NUM(XML_FROM_CHECK)); rb_define_const(eXMLError, "WRITER", INT2NUM(XML_FROM_WRITER)); #if LIBXML_VERSION >= 20621 rb_define_const(eXMLError, "MODULE", INT2NUM(XML_FROM_MODULE)); #endif #if LIBXML_VERSION >= 20632 rb_define_const(eXMLError, "I18N", INT2NUM(XML_FROM_I18N)); rb_define_const(eXMLError, "SCHEMATRONV", INT2NUM(XML_FROM_SCHEMATRONV)); #endif /* errors */ rb_define_const(eXMLError, "OK", INT2NUM(XML_ERR_OK)); rb_define_const(eXMLError, "INTERNAL_ERROR", INT2NUM(XML_ERR_INTERNAL_ERROR)); rb_define_const(eXMLError, "NO_MEMORY", INT2NUM(XML_ERR_NO_MEMORY)); rb_define_const(eXMLError, "DOCUMENT_START", INT2NUM(XML_ERR_DOCUMENT_START)); rb_define_const(eXMLError, "DOCUMENT_EMPTY", INT2NUM(XML_ERR_DOCUMENT_EMPTY)); rb_define_const(eXMLError, "DOCUMENT_END", INT2NUM(XML_ERR_DOCUMENT_END)); rb_define_const(eXMLError, "INVALID_HEX_CHARREF", INT2NUM(XML_ERR_INVALID_HEX_CHARREF)); rb_define_const(eXMLError, "INVALID_DEC_CHARREF", INT2NUM(XML_ERR_INVALID_DEC_CHARREF)); rb_define_const(eXMLError, "INVALID_CHARREF", INT2NUM(XML_ERR_INVALID_CHARREF)); rb_define_const(eXMLError, "INVALID_CHAR", INT2NUM(XML_ERR_INVALID_CHAR)); rb_define_const(eXMLError, "CHARREF_AT_EOF", INT2NUM(XML_ERR_CHARREF_AT_EOF)); rb_define_const(eXMLError, "CHARREF_IN_PROLOG", INT2NUM(XML_ERR_CHARREF_IN_PROLOG)); rb_define_const(eXMLError, "CHARREF_IN_EPILOG", INT2NUM(XML_ERR_CHARREF_IN_EPILOG)); rb_define_const(eXMLError, "CHARREF_IN_DTD", INT2NUM(XML_ERR_CHARREF_IN_DTD)); rb_define_const(eXMLError, "ENTITYREF_AT_EOF", INT2NUM(XML_ERR_ENTITYREF_AT_EOF)); rb_define_const(eXMLError, "ENTITYREF_IN_PROLOG", INT2NUM(XML_ERR_ENTITYREF_IN_PROLOG)); rb_define_const(eXMLError, "ENTITYREF_IN_EPILOG", INT2NUM(XML_ERR_ENTITYREF_IN_EPILOG)); rb_define_const(eXMLError, "ENTITYREF_IN_DTD", INT2NUM(XML_ERR_ENTITYREF_IN_DTD)); rb_define_const(eXMLError, "PEREF_AT_EOF", INT2NUM(XML_ERR_PEREF_AT_EOF)); rb_define_const(eXMLError, "PEREF_IN_PROLOG", INT2NUM(XML_ERR_PEREF_IN_PROLOG)); rb_define_const(eXMLError, "PEREF_IN_EPILOG",INT2NUM(XML_ERR_PEREF_IN_EPILOG)); rb_define_const(eXMLError, "PEREF_IN_INT_SUBSET", INT2NUM(XML_ERR_PEREF_IN_INT_SUBSET)); rb_define_const(eXMLError, "ENTITYREF_NO_NAME", INT2NUM(XML_ERR_ENTITYREF_NO_NAME)); rb_define_const(eXMLError, "ENTITYREF_SEMICOL_MISSING", INT2NUM(XML_ERR_ENTITYREF_SEMICOL_MISSING)); rb_define_const(eXMLError, "PEREF_NO_NAME", INT2NUM(XML_ERR_PEREF_NO_NAME)); rb_define_const(eXMLError, "PEREF_SEMICOL_MISSING", INT2NUM(XML_ERR_PEREF_SEMICOL_MISSING)); rb_define_const(eXMLError, "UNDECLARED_ENTITY", INT2NUM(XML_ERR_UNDECLARED_ENTITY)); rb_define_const(eXMLError, "XML_WAR_UNDECLARED_ENTITY", INT2NUM(XML_WAR_UNDECLARED_ENTITY)); rb_define_const(eXMLError, "UNPARSED_ENTITY", INT2NUM(XML_ERR_UNPARSED_ENTITY)); rb_define_const(eXMLError, "ENTITY_IS_EXTERNAL", INT2NUM(XML_ERR_ENTITY_IS_EXTERNAL)); rb_define_const(eXMLError, "ENTITY_IS_PARAMETER", INT2NUM(XML_ERR_ENTITY_IS_PARAMETER)); rb_define_const(eXMLError, "UNKNOWN_ENCODING", INT2NUM(XML_ERR_UNKNOWN_ENCODING)); rb_define_const(eXMLError, "UNSUPPORTED_ENCODING", INT2NUM(XML_ERR_UNSUPPORTED_ENCODING)); rb_define_const(eXMLError, "STRING_NOT_STARTED", INT2NUM(XML_ERR_STRING_NOT_STARTED)); rb_define_const(eXMLError, "STRING_NOT_CLOSED", INT2NUM(XML_ERR_STRING_NOT_CLOSED)); rb_define_const(eXMLError, "NS_DECL_ERROR", INT2NUM(XML_ERR_NS_DECL_ERROR)); rb_define_const(eXMLError, "ENTITY_NOT_STARTED", INT2NUM(XML_ERR_ENTITY_NOT_STARTED)); rb_define_const(eXMLError, "ENTITY_NOT_FINISHED", INT2NUM(XML_ERR_ENTITY_NOT_FINISHED)); rb_define_const(eXMLError, "LT_IN_ATTRIBUTE", INT2NUM(XML_ERR_LT_IN_ATTRIBUTE)); rb_define_const(eXMLError, "ATTRIBUTE_NOT_STARTED", INT2NUM(XML_ERR_ATTRIBUTE_NOT_STARTED)); rb_define_const(eXMLError, "ATTRIBUTE_NOT_FINISHED", INT2NUM(XML_ERR_ATTRIBUTE_NOT_FINISHED)); rb_define_const(eXMLError, "ATTRIBUTE_WITHOUT_VALUE", INT2NUM(XML_ERR_ATTRIBUTE_WITHOUT_VALUE)); rb_define_const(eXMLError, "ATTRIBUTE_REDEFINED", INT2NUM(XML_ERR_ATTRIBUTE_REDEFINED)); rb_define_const(eXMLError, "LITERAL_NOT_STARTED", INT2NUM(XML_ERR_LITERAL_NOT_STARTED)); rb_define_const(eXMLError, "LITERAL_NOT_FINISHED", INT2NUM(XML_ERR_LITERAL_NOT_FINISHED)); rb_define_const(eXMLError, "COMMENT_NOT_FINISHED", INT2NUM(XML_ERR_COMMENT_NOT_FINISHED)); rb_define_const(eXMLError, "PI_NOT_STARTED", INT2NUM(XML_ERR_PI_NOT_STARTED)); rb_define_const(eXMLError, "PI_NOT_FINISHED", INT2NUM(XML_ERR_PI_NOT_FINISHED)); rb_define_const(eXMLError, "NOTATION_NOT_STARTED", INT2NUM(XML_ERR_NOTATION_NOT_STARTED)); rb_define_const(eXMLError, "NOTATION_NOT_FINISHED", INT2NUM(XML_ERR_NOTATION_NOT_FINISHED)); rb_define_const(eXMLError, "ATTLIST_NOT_STARTED", INT2NUM(XML_ERR_ATTLIST_NOT_STARTED)); rb_define_const(eXMLError, "ATTLIST_NOT_FINISHED", INT2NUM(XML_ERR_ATTLIST_NOT_FINISHED)); rb_define_const(eXMLError, "MIXED_NOT_STARTED", INT2NUM(XML_ERR_MIXED_NOT_STARTED)); rb_define_const(eXMLError, "MIXED_NOT_FINISHED", INT2NUM(XML_ERR_MIXED_NOT_FINISHED)); rb_define_const(eXMLError, "ELEMCONTENT_NOT_STARTED", INT2NUM(XML_ERR_ELEMCONTENT_NOT_STARTED)); rb_define_const(eXMLError, "ELEMCONTENT_NOT_FINISHED", INT2NUM(XML_ERR_ELEMCONTENT_NOT_FINISHED)); rb_define_const(eXMLError, "XMLDECL_NOT_STARTED", INT2NUM(XML_ERR_XMLDECL_NOT_STARTED)); rb_define_const(eXMLError, "XMLDECL_NOT_FINISHED", INT2NUM(XML_ERR_XMLDECL_NOT_FINISHED)); rb_define_const(eXMLError, "CONDSEC_NOT_STARTED", INT2NUM(XML_ERR_CONDSEC_NOT_STARTED)); rb_define_const(eXMLError, "CONDSEC_NOT_FINISHED", INT2NUM(XML_ERR_CONDSEC_NOT_FINISHED)); rb_define_const(eXMLError, "EXT_SUBSET_NOT_FINISHED", INT2NUM(XML_ERR_EXT_SUBSET_NOT_FINISHED)); rb_define_const(eXMLError, "DOCTYPE_NOT_FINISHED", INT2NUM(XML_ERR_DOCTYPE_NOT_FINISHED)); rb_define_const(eXMLError, "MISPLACED_CDATA_END", INT2NUM(XML_ERR_MISPLACED_CDATA_END)); rb_define_const(eXMLError, "CDATA_NOT_FINISHED", INT2NUM(XML_ERR_CDATA_NOT_FINISHED)); rb_define_const(eXMLError, "RESERVED_XML_NAME", INT2NUM(XML_ERR_RESERVED_XML_NAME)); rb_define_const(eXMLError, "SPACE_REQUIRED", INT2NUM(XML_ERR_SPACE_REQUIRED)); rb_define_const(eXMLError, "SEPARATOR_REQUIRED", INT2NUM(XML_ERR_SEPARATOR_REQUIRED)); rb_define_const(eXMLError, "NMTOKEN_REQUIRED", INT2NUM(XML_ERR_NMTOKEN_REQUIRED)); rb_define_const(eXMLError, "NAME_REQUIRED", INT2NUM(XML_ERR_NAME_REQUIRED)); rb_define_const(eXMLError, "PCDATA_REQUIRED", INT2NUM(XML_ERR_PCDATA_REQUIRED)); rb_define_const(eXMLError, "URI_REQUIRED", INT2NUM(XML_ERR_URI_REQUIRED)); rb_define_const(eXMLError, "PUBID_REQUIRED", INT2NUM(XML_ERR_PUBID_REQUIRED)); rb_define_const(eXMLError, "LT_REQUIRED", INT2NUM(XML_ERR_LT_REQUIRED)); rb_define_const(eXMLError, "GT_REQUIRED", INT2NUM(XML_ERR_GT_REQUIRED)); rb_define_const(eXMLError, "LTSLASH_REQUIRED", INT2NUM(XML_ERR_LTSLASH_REQUIRED)); rb_define_const(eXMLError, "EQUAL_REQUIRED", INT2NUM(XML_ERR_EQUAL_REQUIRED)); rb_define_const(eXMLError, "TAG_NAME_MISMATCH", INT2NUM(XML_ERR_TAG_NAME_MISMATCH)); rb_define_const(eXMLError, "TAG_NOT_FINISHED", INT2NUM(XML_ERR_TAG_NOT_FINISHED)); rb_define_const(eXMLError, "STANDALONE_VALUE", INT2NUM(XML_ERR_STANDALONE_VALUE)); rb_define_const(eXMLError, "ENCODING_NAME", INT2NUM(XML_ERR_ENCODING_NAME)); rb_define_const(eXMLError, "HYPHEN_IN_COMMENT", INT2NUM(XML_ERR_HYPHEN_IN_COMMENT)); rb_define_const(eXMLError, "INVALID_ENCODING", INT2NUM(XML_ERR_INVALID_ENCODING)); rb_define_const(eXMLError, "EXT_ENTITY_STANDALONE", INT2NUM(XML_ERR_EXT_ENTITY_STANDALONE)); rb_define_const(eXMLError, "CONDSEC_INVALID", INT2NUM(XML_ERR_CONDSEC_INVALID)); rb_define_const(eXMLError, "VALUE_REQUIRED", INT2NUM(XML_ERR_VALUE_REQUIRED)); rb_define_const(eXMLError, "NOT_WELL_BALANCED", INT2NUM(XML_ERR_NOT_WELL_BALANCED)); rb_define_const(eXMLError, "EXTRA_CONTENT", INT2NUM(XML_ERR_EXTRA_CONTENT)); rb_define_const(eXMLError, "ENTITY_CHAR_ERROR", INT2NUM(XML_ERR_ENTITY_CHAR_ERROR)); rb_define_const(eXMLError, "ENTITY_PE_INTERNAL", INT2NUM(XML_ERR_ENTITY_PE_INTERNAL)); rb_define_const(eXMLError, "ENTITY_LOOP", INT2NUM(XML_ERR_ENTITY_LOOP)); rb_define_const(eXMLError, "ENTITY_BOUNDARY", INT2NUM(XML_ERR_ENTITY_BOUNDARY)); rb_define_const(eXMLError, "INVALID_URI", INT2NUM(XML_ERR_INVALID_URI)); rb_define_const(eXMLError, "URI_FRAGMENT", INT2NUM(XML_ERR_URI_FRAGMENT)); rb_define_const(eXMLError, "XML_WAR_CATALOG_PI", INT2NUM(XML_WAR_CATALOG_PI)); rb_define_const(eXMLError, "NO_DTD", INT2NUM(XML_ERR_NO_DTD)); rb_define_const(eXMLError, "CONDSEC_INVALID_KEYWORD", INT2NUM(XML_ERR_CONDSEC_INVALID_KEYWORD)); rb_define_const(eXMLError, "VERSION_MISSING", INT2NUM(XML_ERR_VERSION_MISSING)); rb_define_const(eXMLError, "XML_WAR_UNKNOWN_VERSION", INT2NUM(XML_WAR_UNKNOWN_VERSION)); rb_define_const(eXMLError, "XML_WAR_LANG_VALUE", INT2NUM(XML_WAR_LANG_VALUE)); rb_define_const(eXMLError, "XML_WAR_NS_URI", INT2NUM(XML_WAR_NS_URI)); rb_define_const(eXMLError, "XML_WAR_NS_URI_RELATIVE", INT2NUM(XML_WAR_NS_URI_RELATIVE)); rb_define_const(eXMLError, "MISSING_ENCODING", INT2NUM(XML_ERR_MISSING_ENCODING)); #if LIBXML_VERSION >= 20620 rb_define_const(eXMLError, "XML_WAR_SPACE_VALUE", INT2NUM(XML_WAR_SPACE_VALUE)); rb_define_const(eXMLError, "NOT_STANDALONE", INT2NUM(XML_ERR_NOT_STANDALONE)); rb_define_const(eXMLError, "ENTITY_PROCESSING", INT2NUM(XML_ERR_ENTITY_PROCESSING)); rb_define_const(eXMLError, "NOTATION_PROCESSING", INT2NUM(XML_ERR_NOTATION_PROCESSING)); rb_define_const(eXMLError, "WAR_NS_COLUMN", INT2NUM(XML_WAR_NS_COLUMN)); rb_define_const(eXMLError, "WAR_ENTITY_REDEFINED", INT2NUM(XML_WAR_ENTITY_REDEFINED)); #endif rb_define_const(eXMLError, "NS_ERR_XML_NAMESPACE", INT2NUM(XML_NS_ERR_XML_NAMESPACE)); rb_define_const(eXMLError, "NS_ERR_UNDEFINED_NAMESPACE", INT2NUM(XML_NS_ERR_UNDEFINED_NAMESPACE)); rb_define_const(eXMLError, "NS_ERR_QNAME", INT2NUM(XML_NS_ERR_QNAME)); rb_define_const(eXMLError, "NS_ERR_ATTRIBUTE_REDEFINED", INT2NUM(XML_NS_ERR_ATTRIBUTE_REDEFINED)); #if LIBXML_VERSION >= 20620 rb_define_const(eXMLError, "NS_ERR_EMPTY", INT2NUM(XML_NS_ERR_EMPTY)); #endif #if LIBXML_VERSION >= 20700 rb_define_const(eXMLError, "NS_ERR_COLON", INT2NUM(XML_NS_ERR_COLON)); #endif rb_define_const(eXMLError, "DTD_ATTRIBUTE_DEFAULT", INT2NUM(XML_DTD_ATTRIBUTE_DEFAULT)); rb_define_const(eXMLError, "DTD_ATTRIBUTE_REDEFINED", INT2NUM(XML_DTD_ATTRIBUTE_REDEFINED)); rb_define_const(eXMLError, "DTD_ATTRIBUTE_VALUE", INT2NUM(XML_DTD_ATTRIBUTE_VALUE)); rb_define_const(eXMLError, "DTD_CONTENT_ERROR", INT2NUM(XML_DTD_CONTENT_ERROR)); rb_define_const(eXMLError, "DTD_CONTENT_MODEL", INT2NUM(XML_DTD_CONTENT_MODEL)); rb_define_const(eXMLError, "DTD_CONTENT_NOT_DETERMINIST", INT2NUM(XML_DTD_CONTENT_NOT_DETERMINIST)); rb_define_const(eXMLError, "DTD_DIFFERENT_PREFIX", INT2NUM(XML_DTD_DIFFERENT_PREFIX)); rb_define_const(eXMLError, "DTD_ELEM_DEFAULT_NAMESPACE", INT2NUM(XML_DTD_ELEM_DEFAULT_NAMESPACE)); rb_define_const(eXMLError, "DTD_ELEM_NAMESPACE", INT2NUM(XML_DTD_ELEM_NAMESPACE)); rb_define_const(eXMLError, "DTD_ELEM_REDEFINED", INT2NUM(XML_DTD_ELEM_REDEFINED)); rb_define_const(eXMLError, "DTD_EMPTY_NOTATION", INT2NUM(XML_DTD_EMPTY_NOTATION)); rb_define_const(eXMLError, "DTD_ENTITY_TYPE", INT2NUM(XML_DTD_ENTITY_TYPE)); rb_define_const(eXMLError, "DTD_ID_FIXED", INT2NUM(XML_DTD_ID_FIXED)); rb_define_const(eXMLError, "DTD_ID_REDEFINED", INT2NUM(XML_DTD_ID_REDEFINED)); rb_define_const(eXMLError, "DTD_ID_SUBSET", INT2NUM(XML_DTD_ID_SUBSET)); rb_define_const(eXMLError, "DTD_INVALID_CHILD", INT2NUM(XML_DTD_INVALID_CHILD)); rb_define_const(eXMLError, "DTD_INVALID_DEFAULT", INT2NUM(XML_DTD_INVALID_DEFAULT)); rb_define_const(eXMLError, "DTD_LOAD_ERROR", INT2NUM(XML_DTD_LOAD_ERROR)); rb_define_const(eXMLError, "DTD_MISSING_ATTRIBUTE", INT2NUM(XML_DTD_MISSING_ATTRIBUTE)); rb_define_const(eXMLError, "DTD_MIXED_CORRUPT", INT2NUM(XML_DTD_MIXED_CORRUPT)); rb_define_const(eXMLError, "DTD_MULTIPLE_ID", INT2NUM(XML_DTD_MULTIPLE_ID)); rb_define_const(eXMLError, "DTD_NO_DOC", INT2NUM(XML_DTD_NO_DOC)); rb_define_const(eXMLError, "DTD_NO_DTD", INT2NUM(XML_DTD_NO_DTD)); rb_define_const(eXMLError, "DTD_NO_ELEM_NAME", INT2NUM(XML_DTD_NO_ELEM_NAME)); rb_define_const(eXMLError, "DTD_NO_PREFIX", INT2NUM(XML_DTD_NO_PREFIX)); rb_define_const(eXMLError, "DTD_NO_ROOT", INT2NUM(XML_DTD_NO_ROOT)); rb_define_const(eXMLError, "DTD_NOTATION_REDEFINED", INT2NUM(XML_DTD_NOTATION_REDEFINED)); rb_define_const(eXMLError, "DTD_NOTATION_VALUE", INT2NUM(XML_DTD_NOTATION_VALUE)); rb_define_const(eXMLError, "DTD_NOT_EMPTY", INT2NUM(XML_DTD_NOT_EMPTY)); rb_define_const(eXMLError, "DTD_NOT_PCDATA", INT2NUM(XML_DTD_NOT_PCDATA)); rb_define_const(eXMLError, "DTD_NOT_STANDALONE", INT2NUM(XML_DTD_NOT_STANDALONE)); rb_define_const(eXMLError, "DTD_ROOT_NAME", INT2NUM(XML_DTD_ROOT_NAME)); rb_define_const(eXMLError, "DTD_STANDALONE_WHITE_SPACE", INT2NUM(XML_DTD_STANDALONE_WHITE_SPACE)); rb_define_const(eXMLError, "DTD_UNKNOWN_ATTRIBUTE", INT2NUM(XML_DTD_UNKNOWN_ATTRIBUTE)); rb_define_const(eXMLError, "DTD_UNKNOWN_ELEM", INT2NUM(XML_DTD_UNKNOWN_ELEM)); rb_define_const(eXMLError, "DTD_UNKNOWN_ENTITY", INT2NUM(XML_DTD_UNKNOWN_ENTITY)); rb_define_const(eXMLError, "DTD_UNKNOWN_ID", INT2NUM(XML_DTD_UNKNOWN_ID)); rb_define_const(eXMLError, "DTD_UNKNOWN_NOTATION", INT2NUM(XML_DTD_UNKNOWN_NOTATION)); rb_define_const(eXMLError, "DTD_STANDALONE_DEFAULTED", INT2NUM(XML_DTD_STANDALONE_DEFAULTED)); rb_define_const(eXMLError, "DTD_XMLID_VALUE", INT2NUM(XML_DTD_XMLID_VALUE)); rb_define_const(eXMLError, "DTD_XMLID_TYPE", INT2NUM(XML_DTD_XMLID_TYPE)); rb_define_const(eXMLError, "HTML_STRUCURE_ERROR", INT2NUM(XML_HTML_STRUCURE_ERROR)); rb_define_const(eXMLError, "HTML_UNKNOWN_TAG", INT2NUM(XML_HTML_UNKNOWN_TAG)); rb_define_const(eXMLError, "RNGP_ANYNAME_ATTR_ANCESTOR", INT2NUM(XML_RNGP_ANYNAME_ATTR_ANCESTOR)); rb_define_const(eXMLError, "RNGP_ATTR_CONFLICT", INT2NUM(XML_RNGP_ATTR_CONFLICT)); rb_define_const(eXMLError, "RNGP_ATTRIBUTE_CHILDREN", INT2NUM(XML_RNGP_ATTRIBUTE_CHILDREN)); rb_define_const(eXMLError, "RNGP_ATTRIBUTE_CONTENT", INT2NUM(XML_RNGP_ATTRIBUTE_CONTENT)); rb_define_const(eXMLError, "RNGP_ATTRIBUTE_EMPTY", INT2NUM(XML_RNGP_ATTRIBUTE_EMPTY)); rb_define_const(eXMLError, "RNGP_ATTRIBUTE_NOOP", INT2NUM(XML_RNGP_ATTRIBUTE_NOOP)); rb_define_const(eXMLError, "RNGP_CHOICE_CONTENT", INT2NUM(XML_RNGP_CHOICE_CONTENT)); rb_define_const(eXMLError, "RNGP_CHOICE_EMPTY", INT2NUM(XML_RNGP_CHOICE_EMPTY)); rb_define_const(eXMLError, "RNGP_CREATE_FAILURE", INT2NUM(XML_RNGP_CREATE_FAILURE)); rb_define_const(eXMLError, "RNGP_DATA_CONTENT", INT2NUM(XML_RNGP_DATA_CONTENT)); rb_define_const(eXMLError, "RNGP_DEF_CHOICE_AND_INTERLEAVE", INT2NUM(XML_RNGP_DEF_CHOICE_AND_INTERLEAVE)); rb_define_const(eXMLError, "RNGP_DEFINE_CREATE_FAILED", INT2NUM(XML_RNGP_DEFINE_CREATE_FAILED)); rb_define_const(eXMLError, "RNGP_DEFINE_EMPTY", INT2NUM(XML_RNGP_DEFINE_EMPTY)); rb_define_const(eXMLError, "RNGP_DEFINE_MISSING", INT2NUM(XML_RNGP_DEFINE_MISSING)); rb_define_const(eXMLError, "RNGP_DEFINE_NAME_MISSING", INT2NUM(XML_RNGP_DEFINE_NAME_MISSING)); rb_define_const(eXMLError, "RNGP_ELEM_CONTENT_EMPTY", INT2NUM(XML_RNGP_ELEM_CONTENT_EMPTY)); rb_define_const(eXMLError, "RNGP_ELEM_CONTENT_ERROR", INT2NUM(XML_RNGP_ELEM_CONTENT_ERROR)); rb_define_const(eXMLError, "RNGP_ELEMENT_EMPTY", INT2NUM(XML_RNGP_ELEMENT_EMPTY)); rb_define_const(eXMLError, "RNGP_ELEMENT_CONTENT", INT2NUM(XML_RNGP_ELEMENT_CONTENT)); rb_define_const(eXMLError, "RNGP_ELEMENT_NAME", INT2NUM(XML_RNGP_ELEMENT_NAME)); rb_define_const(eXMLError, "RNGP_ELEMENT_NO_CONTENT", INT2NUM(XML_RNGP_ELEMENT_NO_CONTENT)); rb_define_const(eXMLError, "RNGP_ELEM_TEXT_CONFLICT", INT2NUM(XML_RNGP_ELEM_TEXT_CONFLICT)); rb_define_const(eXMLError, "RNGP_EMPTY", INT2NUM(XML_RNGP_EMPTY)); rb_define_const(eXMLError, "RNGP_EMPTY_CONSTRUCT", INT2NUM(XML_RNGP_EMPTY_CONSTRUCT)); rb_define_const(eXMLError, "RNGP_EMPTY_CONTENT", INT2NUM(XML_RNGP_EMPTY_CONTENT)); rb_define_const(eXMLError, "RNGP_EMPTY_NOT_EMPTY", INT2NUM(XML_RNGP_EMPTY_NOT_EMPTY)); rb_define_const(eXMLError, "RNGP_ERROR_TYPE_LIB", INT2NUM(XML_RNGP_ERROR_TYPE_LIB)); rb_define_const(eXMLError, "RNGP_EXCEPT_EMPTY", INT2NUM(XML_RNGP_EXCEPT_EMPTY)); rb_define_const(eXMLError, "RNGP_EXCEPT_MISSING", INT2NUM(XML_RNGP_EXCEPT_MISSING)); rb_define_const(eXMLError, "RNGP_EXCEPT_MULTIPLE", INT2NUM(XML_RNGP_EXCEPT_MULTIPLE)); rb_define_const(eXMLError, "RNGP_EXCEPT_NO_CONTENT", INT2NUM(XML_RNGP_EXCEPT_NO_CONTENT)); rb_define_const(eXMLError, "RNGP_EXTERNALREF_EMTPY", INT2NUM(XML_RNGP_EXTERNALREF_EMTPY)); rb_define_const(eXMLError, "RNGP_EXTERNAL_REF_FAILURE", INT2NUM(XML_RNGP_EXTERNAL_REF_FAILURE)); rb_define_const(eXMLError, "RNGP_EXTERNALREF_RECURSE", INT2NUM(XML_RNGP_EXTERNALREF_RECURSE)); rb_define_const(eXMLError, "RNGP_FORBIDDEN_ATTRIBUTE", INT2NUM(XML_RNGP_FORBIDDEN_ATTRIBUTE)); rb_define_const(eXMLError, "RNGP_FOREIGN_ELEMENT", INT2NUM(XML_RNGP_FOREIGN_ELEMENT)); rb_define_const(eXMLError, "RNGP_GRAMMAR_CONTENT", INT2NUM(XML_RNGP_GRAMMAR_CONTENT)); rb_define_const(eXMLError, "RNGP_GRAMMAR_EMPTY", INT2NUM(XML_RNGP_GRAMMAR_EMPTY)); rb_define_const(eXMLError, "RNGP_GRAMMAR_MISSING", INT2NUM(XML_RNGP_GRAMMAR_MISSING)); rb_define_const(eXMLError, "RNGP_GRAMMAR_NO_START", INT2NUM(XML_RNGP_GRAMMAR_NO_START)); rb_define_const(eXMLError, "RNGP_GROUP_ATTR_CONFLICT", INT2NUM(XML_RNGP_GROUP_ATTR_CONFLICT)); rb_define_const(eXMLError, "RNGP_HREF_ERROR", INT2NUM(XML_RNGP_HREF_ERROR)); rb_define_const(eXMLError, "RNGP_INCLUDE_EMPTY", INT2NUM(XML_RNGP_INCLUDE_EMPTY)); rb_define_const(eXMLError, "RNGP_INCLUDE_FAILURE", INT2NUM(XML_RNGP_INCLUDE_FAILURE)); rb_define_const(eXMLError, "RNGP_INCLUDE_RECURSE", INT2NUM(XML_RNGP_INCLUDE_RECURSE)); rb_define_const(eXMLError, "RNGP_INTERLEAVE_ADD", INT2NUM(XML_RNGP_INTERLEAVE_ADD)); rb_define_const(eXMLError, "RNGP_INTERLEAVE_CREATE_FAILED", INT2NUM(XML_RNGP_INTERLEAVE_CREATE_FAILED)); rb_define_const(eXMLError, "RNGP_INTERLEAVE_EMPTY", INT2NUM(XML_RNGP_INTERLEAVE_EMPTY)); rb_define_const(eXMLError, "RNGP_INTERLEAVE_NO_CONTENT", INT2NUM(XML_RNGP_INTERLEAVE_NO_CONTENT)); rb_define_const(eXMLError, "RNGP_INVALID_DEFINE_NAME", INT2NUM(XML_RNGP_INVALID_DEFINE_NAME)); rb_define_const(eXMLError, "RNGP_INVALID_URI", INT2NUM(XML_RNGP_INVALID_URI)); rb_define_const(eXMLError, "RNGP_INVALID_VALUE", INT2NUM(XML_RNGP_INVALID_VALUE)); rb_define_const(eXMLError, "RNGP_MISSING_HREF", INT2NUM(XML_RNGP_MISSING_HREF)); rb_define_const(eXMLError, "RNGP_NAME_MISSING", INT2NUM(XML_RNGP_NAME_MISSING)); rb_define_const(eXMLError, "RNGP_NEED_COMBINE", INT2NUM(XML_RNGP_NEED_COMBINE)); rb_define_const(eXMLError, "RNGP_NOTALLOWED_NOT_EMPTY", INT2NUM(XML_RNGP_NOTALLOWED_NOT_EMPTY)); rb_define_const(eXMLError, "RNGP_NSNAME_ATTR_ANCESTOR", INT2NUM(XML_RNGP_NSNAME_ATTR_ANCESTOR)); rb_define_const(eXMLError, "RNGP_NSNAME_NO_NS", INT2NUM(XML_RNGP_NSNAME_NO_NS)); rb_define_const(eXMLError, "RNGP_PARAM_FORBIDDEN", INT2NUM(XML_RNGP_PARAM_FORBIDDEN)); rb_define_const(eXMLError, "RNGP_PARAM_NAME_MISSING", INT2NUM(XML_RNGP_PARAM_NAME_MISSING)); rb_define_const(eXMLError, "RNGP_PARENTREF_CREATE_FAILED", INT2NUM(XML_RNGP_PARENTREF_CREATE_FAILED)); rb_define_const(eXMLError, "RNGP_PARENTREF_NAME_INVALID", INT2NUM(XML_RNGP_PARENTREF_NAME_INVALID)); rb_define_const(eXMLError, "RNGP_PARENTREF_NO_NAME", INT2NUM(XML_RNGP_PARENTREF_NO_NAME)); rb_define_const(eXMLError, "RNGP_PARENTREF_NO_PARENT", INT2NUM(XML_RNGP_PARENTREF_NO_PARENT)); rb_define_const(eXMLError, "RNGP_PARENTREF_NOT_EMPTY", INT2NUM(XML_RNGP_PARENTREF_NOT_EMPTY)); rb_define_const(eXMLError, "RNGP_PARSE_ERROR", INT2NUM(XML_RNGP_PARSE_ERROR)); rb_define_const(eXMLError, "RNGP_PAT_ANYNAME_EXCEPT_ANYNAME", INT2NUM(XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME)); rb_define_const(eXMLError, "RNGP_PAT_ATTR_ATTR", INT2NUM(XML_RNGP_PAT_ATTR_ATTR)); rb_define_const(eXMLError, "RNGP_PAT_ATTR_ELEM", INT2NUM(XML_RNGP_PAT_ATTR_ELEM)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_ATTR", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_ATTR)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_ELEM", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_ELEM)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_EMPTY", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_EMPTY)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_GROUP", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_GROUP)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_INTERLEAVE", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_LIST", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_LIST)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_ONEMORE", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_ONEMORE)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_REF", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_REF)); rb_define_const(eXMLError, "RNGP_PAT_DATA_EXCEPT_TEXT", INT2NUM(XML_RNGP_PAT_DATA_EXCEPT_TEXT)); rb_define_const(eXMLError, "RNGP_PAT_LIST_ATTR", INT2NUM(XML_RNGP_PAT_LIST_ATTR)); rb_define_const(eXMLError, "RNGP_PAT_LIST_ELEM", INT2NUM(XML_RNGP_PAT_LIST_ELEM)); rb_define_const(eXMLError, "RNGP_PAT_LIST_INTERLEAVE", INT2NUM(XML_RNGP_PAT_LIST_INTERLEAVE)); rb_define_const(eXMLError, "RNGP_PAT_LIST_LIST", INT2NUM(XML_RNGP_PAT_LIST_LIST)); rb_define_const(eXMLError, "RNGP_PAT_LIST_REF", INT2NUM(XML_RNGP_PAT_LIST_REF)); rb_define_const(eXMLError, "RNGP_PAT_LIST_TEXT", INT2NUM(XML_RNGP_PAT_LIST_TEXT)); rb_define_const(eXMLError, "RNGP_PAT_NSNAME_EXCEPT_ANYNAME", INT2NUM(XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME)); rb_define_const(eXMLError, "RNGP_PAT_NSNAME_EXCEPT_NSNAME", INT2NUM(XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME)); rb_define_const(eXMLError, "RNGP_PAT_ONEMORE_GROUP_ATTR", INT2NUM(XML_RNGP_PAT_ONEMORE_GROUP_ATTR)); rb_define_const(eXMLError, "RNGP_PAT_ONEMORE_INTERLEAVE_ATTR", INT2NUM(XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR)); rb_define_const(eXMLError, "RNGP_PAT_START_ATTR", INT2NUM(XML_RNGP_PAT_START_ATTR)); rb_define_const(eXMLError, "RNGP_PAT_START_DATA", INT2NUM(XML_RNGP_PAT_START_DATA)); rb_define_const(eXMLError, "RNGP_PAT_START_EMPTY", INT2NUM(XML_RNGP_PAT_START_EMPTY)); rb_define_const(eXMLError, "RNGP_PAT_START_GROUP", INT2NUM(XML_RNGP_PAT_START_GROUP)); rb_define_const(eXMLError, "RNGP_PAT_START_INTERLEAVE", INT2NUM(XML_RNGP_PAT_START_INTERLEAVE)); rb_define_const(eXMLError, "RNGP_PAT_START_LIST", INT2NUM(XML_RNGP_PAT_START_LIST)); rb_define_const(eXMLError, "RNGP_PAT_START_ONEMORE", INT2NUM(XML_RNGP_PAT_START_ONEMORE)); rb_define_const(eXMLError, "RNGP_PAT_START_TEXT", INT2NUM(XML_RNGP_PAT_START_TEXT)); rb_define_const(eXMLError, "RNGP_PAT_START_VALUE", INT2NUM(XML_RNGP_PAT_START_VALUE)); rb_define_const(eXMLError, "RNGP_PREFIX_UNDEFINED", INT2NUM(XML_RNGP_PREFIX_UNDEFINED)); rb_define_const(eXMLError, "RNGP_REF_CREATE_FAILED", INT2NUM(XML_RNGP_REF_CREATE_FAILED)); rb_define_const(eXMLError, "RNGP_REF_CYCLE", INT2NUM(XML_RNGP_REF_CYCLE)); rb_define_const(eXMLError, "RNGP_REF_NAME_INVALID", INT2NUM(XML_RNGP_REF_NAME_INVALID)); rb_define_const(eXMLError, "RNGP_REF_NO_DEF", INT2NUM(XML_RNGP_REF_NO_DEF)); rb_define_const(eXMLError, "RNGP_REF_NO_NAME", INT2NUM(XML_RNGP_REF_NO_NAME)); rb_define_const(eXMLError, "RNGP_REF_NOT_EMPTY", INT2NUM(XML_RNGP_REF_NOT_EMPTY)); rb_define_const(eXMLError, "RNGP_START_CHOICE_AND_INTERLEAVE", INT2NUM(XML_RNGP_START_CHOICE_AND_INTERLEAVE)); rb_define_const(eXMLError, "RNGP_START_CONTENT", INT2NUM(XML_RNGP_START_CONTENT)); rb_define_const(eXMLError, "RNGP_START_EMPTY", INT2NUM(XML_RNGP_START_EMPTY)); rb_define_const(eXMLError, "RNGP_START_MISSING", INT2NUM(XML_RNGP_START_MISSING)); rb_define_const(eXMLError, "RNGP_TEXT_EXPECTED", INT2NUM(XML_RNGP_TEXT_EXPECTED)); rb_define_const(eXMLError, "RNGP_TEXT_HAS_CHILD", INT2NUM(XML_RNGP_TEXT_HAS_CHILD)); rb_define_const(eXMLError, "RNGP_TYPE_MISSING", INT2NUM(XML_RNGP_TYPE_MISSING)); rb_define_const(eXMLError, "RNGP_TYPE_NOT_FOUND", INT2NUM(XML_RNGP_TYPE_NOT_FOUND)); rb_define_const(eXMLError, "RNGP_TYPE_VALUE", INT2NUM(XML_RNGP_TYPE_VALUE)); rb_define_const(eXMLError, "RNGP_UNKNOWN_ATTRIBUTE", INT2NUM(XML_RNGP_UNKNOWN_ATTRIBUTE)); rb_define_const(eXMLError, "RNGP_UNKNOWN_COMBINE", INT2NUM(XML_RNGP_UNKNOWN_COMBINE)); rb_define_const(eXMLError, "RNGP_UNKNOWN_CONSTRUCT", INT2NUM(XML_RNGP_UNKNOWN_CONSTRUCT)); rb_define_const(eXMLError, "RNGP_UNKNOWN_TYPE_LIB", INT2NUM(XML_RNGP_UNKNOWN_TYPE_LIB)); rb_define_const(eXMLError, "RNGP_URI_FRAGMENT", INT2NUM(XML_RNGP_URI_FRAGMENT)); rb_define_const(eXMLError, "RNGP_URI_NOT_ABSOLUTE", INT2NUM(XML_RNGP_URI_NOT_ABSOLUTE)); rb_define_const(eXMLError, "RNGP_VALUE_EMPTY", INT2NUM(XML_RNGP_VALUE_EMPTY)); rb_define_const(eXMLError, "RNGP_VALUE_NO_CONTENT", INT2NUM(XML_RNGP_VALUE_NO_CONTENT)); rb_define_const(eXMLError, "RNGP_XMLNS_NAME", INT2NUM(XML_RNGP_XMLNS_NAME)); rb_define_const(eXMLError, "RNGP_XML_NS", INT2NUM(XML_RNGP_XML_NS)); rb_define_const(eXMLError, "XPATH_EXPRESSION_OK", INT2NUM(XML_XPATH_EXPRESSION_OK)); rb_define_const(eXMLError, "XPATH_NUMBER_ERROR", INT2NUM(XML_XPATH_NUMBER_ERROR)); rb_define_const(eXMLError, "XPATH_UNFINISHED_LITERAL_ERROR", INT2NUM(XML_XPATH_UNFINISHED_LITERAL_ERROR)); rb_define_const(eXMLError, "XPATH_START_LITERAL_ERROR", INT2NUM(XML_XPATH_START_LITERAL_ERROR)); rb_define_const(eXMLError, "XPATH_VARIABLE_REF_ERROR", INT2NUM(XML_XPATH_VARIABLE_REF_ERROR)); rb_define_const(eXMLError, "XPATH_UNDEF_VARIABLE_ERROR", INT2NUM(XML_XPATH_UNDEF_VARIABLE_ERROR)); rb_define_const(eXMLError, "XPATH_INVALID_PREDICATE_ERROR", INT2NUM(XML_XPATH_INVALID_PREDICATE_ERROR)); rb_define_const(eXMLError, "XPATH_EXPR_ERROR", INT2NUM(XML_XPATH_EXPR_ERROR)); rb_define_const(eXMLError, "XPATH_UNCLOSED_ERROR", INT2NUM(XML_XPATH_UNCLOSED_ERROR)); rb_define_const(eXMLError, "XPATH_UNKNOWN_FUNC_ERROR", INT2NUM(XML_XPATH_UNKNOWN_FUNC_ERROR)); rb_define_const(eXMLError, "XPATH_INVALID_OPERAND", INT2NUM(XML_XPATH_INVALID_OPERAND)); rb_define_const(eXMLError, "XPATH_INVALID_TYPE", INT2NUM(XML_XPATH_INVALID_TYPE)); rb_define_const(eXMLError, "XPATH_INVALID_ARITY", INT2NUM(XML_XPATH_INVALID_ARITY)); rb_define_const(eXMLError, "XPATH_INVALID_CTXT_SIZE", INT2NUM(XML_XPATH_INVALID_CTXT_SIZE)); rb_define_const(eXMLError, "XPATH_INVALID_CTXT_POSITION", INT2NUM(XML_XPATH_INVALID_CTXT_POSITION)); rb_define_const(eXMLError, "XPATH_MEMORY_ERROR", INT2NUM(XML_XPATH_MEMORY_ERROR)); rb_define_const(eXMLError, "XPTR_SYNTAX_ERROR", INT2NUM(XML_XPTR_SYNTAX_ERROR)); rb_define_const(eXMLError, "XPTR_RESOURCE_ERROR", INT2NUM(XML_XPTR_RESOURCE_ERROR)); rb_define_const(eXMLError, "XPTR_SUB_RESOURCE_ERROR", INT2NUM(XML_XPTR_SUB_RESOURCE_ERROR)); rb_define_const(eXMLError, "XPATH_UNDEF_PREFIX_ERROR", INT2NUM(XML_XPATH_UNDEF_PREFIX_ERROR)); rb_define_const(eXMLError, "XPATH_ENCODING_ERROR", INT2NUM(XML_XPATH_ENCODING_ERROR)); rb_define_const(eXMLError, "XPATH_INVALID_CHAR_ERROR", INT2NUM(XML_XPATH_INVALID_CHAR_ERROR)); rb_define_const(eXMLError, "TREE_INVALID_HEX", INT2NUM(XML_TREE_INVALID_HEX)); rb_define_const(eXMLError, "TREE_INVALID_DEC", INT2NUM(XML_TREE_INVALID_DEC)); rb_define_const(eXMLError, "TREE_UNTERMINATED_ENTITY", INT2NUM(XML_TREE_UNTERMINATED_ENTITY)); #if LIBXML_VERSION >= 20632 rb_define_const(eXMLError, "TREE_NOT_UTF8", INT2NUM(XML_TREE_NOT_UTF8)); #endif rb_define_const(eXMLError, "SAVE_NOT_UTF8", INT2NUM(XML_SAVE_NOT_UTF8)); rb_define_const(eXMLError, "SAVE_CHAR_INVALID", INT2NUM(XML_SAVE_CHAR_INVALID)); rb_define_const(eXMLError, "SAVE_NO_DOCTYPE", INT2NUM(XML_SAVE_NO_DOCTYPE)); rb_define_const(eXMLError, "SAVE_UNKNOWN_ENCODING", INT2NUM(XML_SAVE_UNKNOWN_ENCODING)); rb_define_const(eXMLError, "REGEXP_COMPILE_ERROR", INT2NUM(XML_REGEXP_COMPILE_ERROR)); rb_define_const(eXMLError, "IO_UNKNOWN", INT2NUM(XML_IO_UNKNOWN)); rb_define_const(eXMLError, "IO_EACCES", INT2NUM(XML_IO_EACCES)); rb_define_const(eXMLError, "IO_EAGAIN", INT2NUM(XML_IO_EAGAIN)); rb_define_const(eXMLError, "IO_EBADF", INT2NUM(XML_IO_EBADF)); rb_define_const(eXMLError, "IO_EBADMSG", INT2NUM(XML_IO_EBADMSG)); rb_define_const(eXMLError, "IO_EBUSY", INT2NUM(XML_IO_EBUSY)); rb_define_const(eXMLError, "IO_ECANCELED", INT2NUM(XML_IO_ECANCELED)); rb_define_const(eXMLError, "IO_ECHILD", INT2NUM(XML_IO_ECHILD)); rb_define_const(eXMLError, "IO_EDEADLK", INT2NUM(XML_IO_EDEADLK)); rb_define_const(eXMLError, "IO_EDOM", INT2NUM(XML_IO_EDOM)); rb_define_const(eXMLError, "IO_EEXIST", INT2NUM(XML_IO_EEXIST)); rb_define_const(eXMLError, "IO_EFAULT", INT2NUM(XML_IO_EFAULT)); rb_define_const(eXMLError, "IO_EFBIG", INT2NUM(XML_IO_EFBIG)); rb_define_const(eXMLError, "IO_EINPROGRESS", INT2NUM(XML_IO_EINPROGRESS)); rb_define_const(eXMLError, "IO_EINTR", INT2NUM(XML_IO_EINTR)); rb_define_const(eXMLError, "IO_EINVAL", INT2NUM(XML_IO_EINVAL)); rb_define_const(eXMLError, "IO_EIO", INT2NUM(XML_IO_EIO)); rb_define_const(eXMLError, "IO_EISDIR", INT2NUM(XML_IO_EISDIR)); rb_define_const(eXMLError, "IO_EMFILE", INT2NUM(XML_IO_EMFILE)); rb_define_const(eXMLError, "IO_EMLINK", INT2NUM(XML_IO_EMLINK)); rb_define_const(eXMLError, "IO_EMSGSIZE", INT2NUM(XML_IO_EMSGSIZE)); rb_define_const(eXMLError, "IO_ENAMETOOLONG", INT2NUM(XML_IO_ENAMETOOLONG)); rb_define_const(eXMLError, "IO_ENFILE", INT2NUM(XML_IO_ENFILE)); rb_define_const(eXMLError, "IO_ENODEV", INT2NUM(XML_IO_ENODEV)); rb_define_const(eXMLError, "IO_ENOENT", INT2NUM(XML_IO_ENOENT)); rb_define_const(eXMLError, "IO_ENOEXEC", INT2NUM(XML_IO_ENOEXEC)); rb_define_const(eXMLError, "IO_ENOLCK", INT2NUM(XML_IO_ENOLCK)); rb_define_const(eXMLError, "IO_ENOMEM", INT2NUM(XML_IO_ENOMEM)); rb_define_const(eXMLError, "IO_ENOSPC", INT2NUM(XML_IO_ENOSPC)); rb_define_const(eXMLError, "IO_ENOSYS", INT2NUM(XML_IO_ENOSYS)); rb_define_const(eXMLError, "IO_ENOTDIR", INT2NUM(XML_IO_ENOTDIR)); rb_define_const(eXMLError, "IO_ENOTEMPTY", INT2NUM(XML_IO_ENOTEMPTY)); rb_define_const(eXMLError, "IO_ENOTSUP", INT2NUM(XML_IO_ENOTSUP)); rb_define_const(eXMLError, "IO_ENOTTY", INT2NUM(XML_IO_ENOTTY)); rb_define_const(eXMLError, "IO_ENXIO", INT2NUM(XML_IO_ENXIO)); rb_define_const(eXMLError, "IO_EPERM", INT2NUM(XML_IO_EPERM)); rb_define_const(eXMLError, "IO_EPIPE", INT2NUM(XML_IO_EPIPE)); rb_define_const(eXMLError, "IO_ERANGE", INT2NUM(XML_IO_ERANGE)); rb_define_const(eXMLError, "IO_EROFS", INT2NUM(XML_IO_EROFS)); rb_define_const(eXMLError, "IO_ESPIPE", INT2NUM(XML_IO_ESPIPE)); rb_define_const(eXMLError, "IO_ESRCH", INT2NUM(XML_IO_ESRCH)); rb_define_const(eXMLError, "IO_ETIMEDOUT", INT2NUM(XML_IO_ETIMEDOUT)); rb_define_const(eXMLError, "IO_EXDEV", INT2NUM(XML_IO_EXDEV)); rb_define_const(eXMLError, "IO_NETWORK_ATTEMPT", INT2NUM(XML_IO_NETWORK_ATTEMPT)); rb_define_const(eXMLError, "IO_ENCODER", INT2NUM(XML_IO_ENCODER)); rb_define_const(eXMLError, "IO_FLUSH", INT2NUM(XML_IO_FLUSH)); rb_define_const(eXMLError, "IO_WRITE", INT2NUM(XML_IO_WRITE)); rb_define_const(eXMLError, "IO_NO_INPUT", INT2NUM(XML_IO_NO_INPUT)); rb_define_const(eXMLError, "IO_BUFFER_FULL", INT2NUM(XML_IO_BUFFER_FULL)); rb_define_const(eXMLError, "IO_LOAD_ERROR", INT2NUM(XML_IO_LOAD_ERROR)); rb_define_const(eXMLError, "IO_ENOTSOCK", INT2NUM(XML_IO_ENOTSOCK)); rb_define_const(eXMLError, "IO_EISCONN", INT2NUM(XML_IO_EISCONN)); rb_define_const(eXMLError, "IO_ECONNREFUSED", INT2NUM(XML_IO_ECONNREFUSED)); rb_define_const(eXMLError, "IO_ENETUNREACH", INT2NUM(XML_IO_ENETUNREACH)); rb_define_const(eXMLError, "IO_EADDRINUSE", INT2NUM(XML_IO_EADDRINUSE)); rb_define_const(eXMLError, "IO_EALREADY", INT2NUM(XML_IO_EALREADY)); rb_define_const(eXMLError, "IO_EAFNOSUPPORT", INT2NUM(XML_IO_EAFNOSUPPORT)); rb_define_const(eXMLError, "XINCLUDE_RECURSION", INT2NUM(XML_XINCLUDE_RECURSION)); rb_define_const(eXMLError, "XINCLUDE_PARSE_VALUE", INT2NUM(XML_XINCLUDE_PARSE_VALUE)); rb_define_const(eXMLError, "XINCLUDE_ENTITY_DEF_MISMATCH", INT2NUM(XML_XINCLUDE_ENTITY_DEF_MISMATCH)); rb_define_const(eXMLError, "XINCLUDE_NO_HREF", INT2NUM(XML_XINCLUDE_NO_HREF)); rb_define_const(eXMLError, "XINCLUDE_NO_FALLBACK", INT2NUM(XML_XINCLUDE_NO_FALLBACK)); rb_define_const(eXMLError, "XINCLUDE_HREF_URI", INT2NUM(XML_XINCLUDE_HREF_URI)); rb_define_const(eXMLError, "XINCLUDE_TEXT_FRAGMENT", INT2NUM(XML_XINCLUDE_TEXT_FRAGMENT)); rb_define_const(eXMLError, "XINCLUDE_TEXT_DOCUMENT", INT2NUM(XML_XINCLUDE_TEXT_DOCUMENT)); rb_define_const(eXMLError, "XINCLUDE_INVALID_CHAR", INT2NUM(XML_XINCLUDE_INVALID_CHAR)); rb_define_const(eXMLError, "XINCLUDE_BUILD_FAILED", INT2NUM(XML_XINCLUDE_BUILD_FAILED)); rb_define_const(eXMLError, "XINCLUDE_UNKNOWN_ENCODING", INT2NUM(XML_XINCLUDE_UNKNOWN_ENCODING)); rb_define_const(eXMLError, "XINCLUDE_MULTIPLE_ROOT", INT2NUM(XML_XINCLUDE_MULTIPLE_ROOT)); rb_define_const(eXMLError, "XINCLUDE_XPTR_FAILED", INT2NUM(XML_XINCLUDE_XPTR_FAILED)); rb_define_const(eXMLError, "XINCLUDE_XPTR_RESULT", INT2NUM(XML_XINCLUDE_XPTR_RESULT)); rb_define_const(eXMLError, "XINCLUDE_INCLUDE_IN_INCLUDE", INT2NUM(XML_XINCLUDE_INCLUDE_IN_INCLUDE)); rb_define_const(eXMLError, "XINCLUDE_FALLBACKS_IN_INCLUDE", INT2NUM(XML_XINCLUDE_FALLBACKS_IN_INCLUDE)); rb_define_const(eXMLError, "XINCLUDE_FALLBACK_NOT_IN_INCLUDE", INT2NUM(XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE)); rb_define_const(eXMLError, "XINCLUDE_DEPRECATED_NS", INT2NUM(XML_XINCLUDE_DEPRECATED_NS)); rb_define_const(eXMLError, "XINCLUDE_FRAGMENT_ID", INT2NUM(XML_XINCLUDE_FRAGMENT_ID)); rb_define_const(eXMLError, "CATALOG_MISSING_ATTR", INT2NUM(XML_CATALOG_MISSING_ATTR)); rb_define_const(eXMLError, "CATALOG_ENTRY_BROKEN", INT2NUM(XML_CATALOG_ENTRY_BROKEN)); rb_define_const(eXMLError, "CATALOG_PREFER_VALUE", INT2NUM(XML_CATALOG_PREFER_VALUE)); rb_define_const(eXMLError, "CATALOG_NOT_CATALOG", INT2NUM(XML_CATALOG_NOT_CATALOG)); rb_define_const(eXMLError, "CATALOG_RECURSION", INT2NUM(XML_CATALOG_RECURSION)); rb_define_const(eXMLError, "SCHEMAP_PREFIX_UNDEFINED", INT2NUM(XML_SCHEMAP_PREFIX_UNDEFINED)); rb_define_const(eXMLError, "SCHEMAP_ATTRFORMDEFAULT_VALUE", INT2NUM(XML_SCHEMAP_ATTRFORMDEFAULT_VALUE)); rb_define_const(eXMLError, "SCHEMAP_ATTRGRP_NONAME_NOREF", INT2NUM(XML_SCHEMAP_ATTRGRP_NONAME_NOREF)); rb_define_const(eXMLError, "SCHEMAP_ATTR_NONAME_NOREF", INT2NUM(XML_SCHEMAP_ATTR_NONAME_NOREF)); rb_define_const(eXMLError, "SCHEMAP_COMPLEXTYPE_NONAME_NOREF", INT2NUM(XML_SCHEMAP_COMPLEXTYPE_NONAME_NOREF)); rb_define_const(eXMLError, "SCHEMAP_ELEMFORMDEFAULT_VALUE", INT2NUM(XML_SCHEMAP_ELEMFORMDEFAULT_VALUE)); rb_define_const(eXMLError, "SCHEMAP_ELEM_NONAME_NOREF", INT2NUM(XML_SCHEMAP_ELEM_NONAME_NOREF)); rb_define_const(eXMLError, "SCHEMAP_EXTENSION_NO_BASE", INT2NUM(XML_SCHEMAP_EXTENSION_NO_BASE)); rb_define_const(eXMLError, "SCHEMAP_FACET_NO_VALUE", INT2NUM(XML_SCHEMAP_FACET_NO_VALUE)); rb_define_const(eXMLError, "SCHEMAP_FAILED_BUILD_IMPORT", INT2NUM(XML_SCHEMAP_FAILED_BUILD_IMPORT)); rb_define_const(eXMLError, "SCHEMAP_GROUP_NONAME_NOREF", INT2NUM(XML_SCHEMAP_GROUP_NONAME_NOREF)); rb_define_const(eXMLError, "SCHEMAP_IMPORT_NAMESPACE_NOT_URI", INT2NUM(XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI)); rb_define_const(eXMLError, "SCHEMAP_IMPORT_REDEFINE_NSNAME", INT2NUM(XML_SCHEMAP_IMPORT_REDEFINE_NSNAME)); rb_define_const(eXMLError, "SCHEMAP_IMPORT_SCHEMA_NOT_URI", INT2NUM(XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI)); rb_define_const(eXMLError, "SCHEMAP_INVALID_BOOLEAN", INT2NUM(XML_SCHEMAP_INVALID_BOOLEAN)); rb_define_const(eXMLError, "SCHEMAP_INVALID_ENUM", INT2NUM(XML_SCHEMAP_INVALID_ENUM)); rb_define_const(eXMLError, "SCHEMAP_INVALID_FACET", INT2NUM(XML_SCHEMAP_INVALID_FACET)); rb_define_const(eXMLError, "SCHEMAP_INVALID_FACET_VALUE", INT2NUM(XML_SCHEMAP_INVALID_FACET_VALUE)); rb_define_const(eXMLError, "SCHEMAP_INVALID_MAXOCCURS", INT2NUM(XML_SCHEMAP_INVALID_MAXOCCURS)); rb_define_const(eXMLError, "SCHEMAP_INVALID_MINOCCURS", INT2NUM(XML_SCHEMAP_INVALID_MINOCCURS)); rb_define_const(eXMLError, "SCHEMAP_INVALID_REF_AND_SUBTYPE", INT2NUM(XML_SCHEMAP_INVALID_REF_AND_SUBTYPE)); rb_define_const(eXMLError, "SCHEMAP_INVALID_WHITE_SPACE", INT2NUM(XML_SCHEMAP_INVALID_WHITE_SPACE)); rb_define_const(eXMLError, "SCHEMAP_NOATTR_NOREF", INT2NUM(XML_SCHEMAP_NOATTR_NOREF)); rb_define_const(eXMLError, "SCHEMAP_NOTATION_NO_NAME", INT2NUM(XML_SCHEMAP_NOTATION_NO_NAME)); rb_define_const(eXMLError, "SCHEMAP_NOTYPE_NOREF", INT2NUM(XML_SCHEMAP_NOTYPE_NOREF)); rb_define_const(eXMLError, "SCHEMAP_REF_AND_SUBTYPE", INT2NUM(XML_SCHEMAP_REF_AND_SUBTYPE)); rb_define_const(eXMLError, "SCHEMAP_RESTRICTION_NONAME_NOREF", INT2NUM(XML_SCHEMAP_RESTRICTION_NONAME_NOREF)); rb_define_const(eXMLError, "SCHEMAP_SIMPLETYPE_NONAME", INT2NUM(XML_SCHEMAP_SIMPLETYPE_NONAME)); rb_define_const(eXMLError, "SCHEMAP_TYPE_AND_SUBTYPE", INT2NUM(XML_SCHEMAP_TYPE_AND_SUBTYPE)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_ALL_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_ALL_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_ATTR_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_ATTR_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_ATTRGRP_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP", INT2NUM(XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_BASE_TYPE", INT2NUM(XML_SCHEMAP_UNKNOWN_BASE_TYPE)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_CHOICE_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_CHOICE_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_ELEM_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_ELEM_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_EXTENSION_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_FACET_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_FACET_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_FACET_TYPE", INT2NUM(XML_SCHEMAP_UNKNOWN_FACET_TYPE)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_GROUP_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_GROUP_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_IMPORT_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_IMPORT_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_LIST_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_LIST_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_NOTATION_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_NOTATION_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_REF", INT2NUM(XML_SCHEMAP_UNKNOWN_REF)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_RESTRICTION_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_SCHEMAS_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_SEQUENCE_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_TYPE", INT2NUM(XML_SCHEMAP_UNKNOWN_TYPE)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_UNION_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_UNION_CHILD)); rb_define_const(eXMLError, "SCHEMAP_ELEM_DEFAULT_FIXED", INT2NUM(XML_SCHEMAP_ELEM_DEFAULT_FIXED)); rb_define_const(eXMLError, "SCHEMAP_REGEXP_INVALID", INT2NUM(XML_SCHEMAP_REGEXP_INVALID)); rb_define_const(eXMLError, "SCHEMAP_FAILED_LOAD", INT2NUM(XML_SCHEMAP_FAILED_LOAD)); rb_define_const(eXMLError, "SCHEMAP_NOTHING_TO_PARSE", INT2NUM(XML_SCHEMAP_NOTHING_TO_PARSE)); rb_define_const(eXMLError, "SCHEMAP_NOROOT", INT2NUM(XML_SCHEMAP_NOROOT)); rb_define_const(eXMLError, "SCHEMAP_REDEFINED_GROUP", INT2NUM(XML_SCHEMAP_REDEFINED_GROUP)); rb_define_const(eXMLError, "SCHEMAP_REDEFINED_TYPE", INT2NUM(XML_SCHEMAP_REDEFINED_TYPE)); rb_define_const(eXMLError, "SCHEMAP_REDEFINED_ELEMENT", INT2NUM(XML_SCHEMAP_REDEFINED_ELEMENT)); rb_define_const(eXMLError, "SCHEMAP_REDEFINED_ATTRGROUP", INT2NUM(XML_SCHEMAP_REDEFINED_ATTRGROUP)); rb_define_const(eXMLError, "SCHEMAP_REDEFINED_ATTR", INT2NUM(XML_SCHEMAP_REDEFINED_ATTR)); rb_define_const(eXMLError, "SCHEMAP_REDEFINED_NOTATION", INT2NUM(XML_SCHEMAP_REDEFINED_NOTATION)); rb_define_const(eXMLError, "SCHEMAP_FAILED_PARSE", INT2NUM(XML_SCHEMAP_FAILED_PARSE)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_PREFIX", INT2NUM(XML_SCHEMAP_UNKNOWN_PREFIX)); rb_define_const(eXMLError, "SCHEMAP_DEF_AND_PREFIX", INT2NUM(XML_SCHEMAP_DEF_AND_PREFIX)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_INCLUDE_CHILD", INT2NUM(XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD)); rb_define_const(eXMLError, "SCHEMAP_INCLUDE_SCHEMA_NOT_URI", INT2NUM(XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI)); rb_define_const(eXMLError, "SCHEMAP_INCLUDE_SCHEMA_NO_URI", INT2NUM(XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI)); rb_define_const(eXMLError, "SCHEMAP_NOT_SCHEMA", INT2NUM(XML_SCHEMAP_NOT_SCHEMA)); rb_define_const(eXMLError, "SCHEMAP_UNKNOWN_MEMBER_TYPE", INT2NUM(XML_SCHEMAP_UNKNOWN_MEMBER_TYPE)); rb_define_const(eXMLError, "SCHEMAP_INVALID_ATTR_USE", INT2NUM(XML_SCHEMAP_INVALID_ATTR_USE)); rb_define_const(eXMLError, "SCHEMAP_RECURSIVE", INT2NUM(XML_SCHEMAP_RECURSIVE)); rb_define_const(eXMLError, "SCHEMAP_SUPERNUMEROUS_LIST_ITEM_TYPE", INT2NUM(XML_SCHEMAP_SUPERNUMEROUS_LIST_ITEM_TYPE)); rb_define_const(eXMLError, "SCHEMAP_INVALID_ATTR_COMBINATION", INT2NUM(XML_SCHEMAP_INVALID_ATTR_COMBINATION)); rb_define_const(eXMLError, "SCHEMAP_INVALID_ATTR_INLINE_COMBINATION", INT2NUM(XML_SCHEMAP_INVALID_ATTR_INLINE_COMBINATION)); rb_define_const(eXMLError, "SCHEMAP_MISSING_SIMPLETYPE_CHILD", INT2NUM(XML_SCHEMAP_MISSING_SIMPLETYPE_CHILD)); rb_define_const(eXMLError, "SCHEMAP_INVALID_ATTR_NAME", INT2NUM(XML_SCHEMAP_INVALID_ATTR_NAME)); rb_define_const(eXMLError, "SCHEMAP_REF_AND_CONTENT", INT2NUM(XML_SCHEMAP_REF_AND_CONTENT)); rb_define_const(eXMLError, "SCHEMAP_CT_PROPS_CORRECT_1", INT2NUM(XML_SCHEMAP_CT_PROPS_CORRECT_1)); rb_define_const(eXMLError, "SCHEMAP_CT_PROPS_CORRECT_2", INT2NUM(XML_SCHEMAP_CT_PROPS_CORRECT_2)); rb_define_const(eXMLError, "SCHEMAP_CT_PROPS_CORRECT_3", INT2NUM(XML_SCHEMAP_CT_PROPS_CORRECT_3)); rb_define_const(eXMLError, "SCHEMAP_CT_PROPS_CORRECT_4", INT2NUM(XML_SCHEMAP_CT_PROPS_CORRECT_4)); rb_define_const(eXMLError, "SCHEMAP_CT_PROPS_CORRECT_5", INT2NUM(XML_SCHEMAP_CT_PROPS_CORRECT_5)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_1", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_1", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_1)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_2", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_2)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_2_2", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_2)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_3", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_3)); rb_define_const(eXMLError, "SCHEMAP_WILDCARD_INVALID_NS_MEMBER", INT2NUM(XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER)); rb_define_const(eXMLError, "SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE", INT2NUM(XML_SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE)); rb_define_const(eXMLError, "SCHEMAP_UNION_NOT_EXPRESSIBLE", INT2NUM(XML_SCHEMAP_UNION_NOT_EXPRESSIBLE)); rb_define_const(eXMLError, "SCHEMAP_SRC_IMPORT_3_1", INT2NUM(XML_SCHEMAP_SRC_IMPORT_3_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_IMPORT_3_2", INT2NUM(XML_SCHEMAP_SRC_IMPORT_3_2)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_4_1", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_1)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_4_2", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_2)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_4_3", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_3)); rb_define_const(eXMLError, "SCHEMAP_COS_CT_EXTENDS_1_3", INT2NUM(XML_SCHEMAP_COS_CT_EXTENDS_1_3)); rb_define_const(eXMLError, "SCHEMAV_NOROOT", INT2NUM(XML_SCHEMAV_NOROOT)); rb_define_const(eXMLError, "SCHEMAV_UNDECLAREDELEM", INT2NUM(XML_SCHEMAV_UNDECLAREDELEM)); rb_define_const(eXMLError, "SCHEMAV_NOTTOPLEVEL", INT2NUM(XML_SCHEMAV_NOTTOPLEVEL)); rb_define_const(eXMLError, "SCHEMAV_MISSING", INT2NUM(XML_SCHEMAV_MISSING)); rb_define_const(eXMLError, "SCHEMAV_WRONGELEM", INT2NUM(XML_SCHEMAV_WRONGELEM)); rb_define_const(eXMLError, "SCHEMAV_NOTYPE", INT2NUM(XML_SCHEMAV_NOTYPE)); rb_define_const(eXMLError, "SCHEMAV_NOROLLBACK", INT2NUM(XML_SCHEMAV_NOROLLBACK)); rb_define_const(eXMLError, "SCHEMAV_ISABSTRACT", INT2NUM(XML_SCHEMAV_ISABSTRACT)); rb_define_const(eXMLError, "SCHEMAV_NOTEMPTY", INT2NUM(XML_SCHEMAV_NOTEMPTY)); rb_define_const(eXMLError, "SCHEMAV_ELEMCONT", INT2NUM(XML_SCHEMAV_ELEMCONT)); rb_define_const(eXMLError, "SCHEMAV_HAVEDEFAULT", INT2NUM(XML_SCHEMAV_HAVEDEFAULT)); rb_define_const(eXMLError, "SCHEMAV_NOTNILLABLE", INT2NUM(XML_SCHEMAV_NOTNILLABLE)); rb_define_const(eXMLError, "SCHEMAV_EXTRACONTENT", INT2NUM(XML_SCHEMAV_EXTRACONTENT)); rb_define_const(eXMLError, "SCHEMAV_INVALIDATTR", INT2NUM(XML_SCHEMAV_INVALIDATTR)); rb_define_const(eXMLError, "SCHEMAV_INVALIDELEM", INT2NUM(XML_SCHEMAV_INVALIDELEM)); rb_define_const(eXMLError, "SCHEMAV_NOTDETERMINIST", INT2NUM(XML_SCHEMAV_NOTDETERMINIST)); rb_define_const(eXMLError, "SCHEMAV_CONSTRUCT", INT2NUM(XML_SCHEMAV_CONSTRUCT)); rb_define_const(eXMLError, "SCHEMAV_INTERNAL", INT2NUM(XML_SCHEMAV_INTERNAL)); rb_define_const(eXMLError, "SCHEMAV_NOTSIMPLE", INT2NUM(XML_SCHEMAV_NOTSIMPLE)); rb_define_const(eXMLError, "SCHEMAV_ATTRUNKNOWN", INT2NUM(XML_SCHEMAV_ATTRUNKNOWN)); rb_define_const(eXMLError, "SCHEMAV_ATTRINVALID", INT2NUM(XML_SCHEMAV_ATTRINVALID)); rb_define_const(eXMLError, "SCHEMAV_VALUE", INT2NUM(XML_SCHEMAV_VALUE)); rb_define_const(eXMLError, "SCHEMAV_FACET", INT2NUM(XML_SCHEMAV_FACET)); rb_define_const(eXMLError, "SCHEMAV_CVC_DATATYPE_VALID_1_2_1", INT2NUM(XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_DATATYPE_VALID_1_2_2", INT2NUM(XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_DATATYPE_VALID_1_2_3", INT2NUM(XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3)); rb_define_const(eXMLError, "SCHEMAV_CVC_TYPE_3_1_1", INT2NUM(XML_SCHEMAV_CVC_TYPE_3_1_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_TYPE_3_1_2", INT2NUM(XML_SCHEMAV_CVC_TYPE_3_1_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_FACET_VALID", INT2NUM(XML_SCHEMAV_CVC_FACET_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_LENGTH_VALID", INT2NUM(XML_SCHEMAV_CVC_LENGTH_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_MINLENGTH_VALID", INT2NUM(XML_SCHEMAV_CVC_MINLENGTH_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_MAXLENGTH_VALID", INT2NUM(XML_SCHEMAV_CVC_MAXLENGTH_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_MININCLUSIVE_VALID", INT2NUM(XML_SCHEMAV_CVC_MININCLUSIVE_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_MAXINCLUSIVE_VALID", INT2NUM(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_MINEXCLUSIVE_VALID", INT2NUM(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_MAXEXCLUSIVE_VALID", INT2NUM(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_TOTALDIGITS_VALID", INT2NUM(XML_SCHEMAV_CVC_TOTALDIGITS_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_FRACTIONDIGITS_VALID", INT2NUM(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_PATTERN_VALID", INT2NUM(XML_SCHEMAV_CVC_PATTERN_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_ENUMERATION_VALID", INT2NUM(XML_SCHEMAV_CVC_ENUMERATION_VALID)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_2_1", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_2_2", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_2_3", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_2_3)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_2_4", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_2_4)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_1", INT2NUM(XML_SCHEMAV_CVC_ELT_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_2", INT2NUM(XML_SCHEMAV_CVC_ELT_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_3_1", INT2NUM(XML_SCHEMAV_CVC_ELT_3_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_3_2_1", INT2NUM(XML_SCHEMAV_CVC_ELT_3_2_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_3_2_2", INT2NUM(XML_SCHEMAV_CVC_ELT_3_2_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_4_1", INT2NUM(XML_SCHEMAV_CVC_ELT_4_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_4_2", INT2NUM(XML_SCHEMAV_CVC_ELT_4_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_4_3", INT2NUM(XML_SCHEMAV_CVC_ELT_4_3)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_5_1_1", INT2NUM(XML_SCHEMAV_CVC_ELT_5_1_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_5_1_2", INT2NUM(XML_SCHEMAV_CVC_ELT_5_1_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_5_2_1", INT2NUM(XML_SCHEMAV_CVC_ELT_5_2_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_5_2_2_1", INT2NUM(XML_SCHEMAV_CVC_ELT_5_2_2_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_5_2_2_2_1", INT2NUM(XML_SCHEMAV_CVC_ELT_5_2_2_2_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_5_2_2_2_2", INT2NUM(XML_SCHEMAV_CVC_ELT_5_2_2_2_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_6", INT2NUM(XML_SCHEMAV_CVC_ELT_6)); rb_define_const(eXMLError, "SCHEMAV_CVC_ELT_7",INT2NUM(XML_SCHEMAV_CVC_ELT_7)); rb_define_const(eXMLError, "SCHEMAV_CVC_ATTRIBUTE_1", INT2NUM(XML_SCHEMAV_CVC_ATTRIBUTE_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_ATTRIBUTE_2", INT2NUM(XML_SCHEMAV_CVC_ATTRIBUTE_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_ATTRIBUTE_3", INT2NUM(XML_SCHEMAV_CVC_ATTRIBUTE_3)); rb_define_const(eXMLError, "SCHEMAV_CVC_ATTRIBUTE_4", INT2NUM(XML_SCHEMAV_CVC_ATTRIBUTE_4)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_3_1", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_3_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_3_2_1", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_3_2_2", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_2)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_4", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_4)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_5_1", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_5_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_5_2", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_5_2)); rb_define_const(eXMLError, "SCHEMAV_ELEMENT_CONTENT", INT2NUM(XML_SCHEMAV_ELEMENT_CONTENT)); rb_define_const(eXMLError, "SCHEMAV_DOCUMENT_ELEMENT_MISSING", INT2NUM(XML_SCHEMAV_DOCUMENT_ELEMENT_MISSING)); rb_define_const(eXMLError, "SCHEMAV_CVC_COMPLEX_TYPE_1", INT2NUM(XML_SCHEMAV_CVC_COMPLEX_TYPE_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_AU", INT2NUM(XML_SCHEMAV_CVC_AU)); rb_define_const(eXMLError, "SCHEMAV_CVC_TYPE_1", INT2NUM(XML_SCHEMAV_CVC_TYPE_1)); rb_define_const(eXMLError, "SCHEMAV_CVC_TYPE_2", INT2NUM(XML_SCHEMAV_CVC_TYPE_2)); #if LIBXML_VERSION >= 20618 rb_define_const(eXMLError, "SCHEMAV_CVC_IDC", INT2NUM(XML_SCHEMAV_CVC_IDC)); rb_define_const(eXMLError, "SCHEMAV_CVC_WILDCARD", INT2NUM(XML_SCHEMAV_CVC_WILDCARD)); #endif #if LIBXML_VERSION >= 20631 rb_define_const(eXMLError, "SCHEMAV_MISC", INT2NUM(XML_SCHEMAV_MISC)); #endif rb_define_const(eXMLError, "XPTR_UNKNOWN_SCHEME", INT2NUM(XML_XPTR_UNKNOWN_SCHEME)); rb_define_const(eXMLError, "XPTR_CHILDSEQ_START", INT2NUM(XML_XPTR_CHILDSEQ_START)); rb_define_const(eXMLError, "XPTR_EVAL_FAILED", INT2NUM(XML_XPTR_EVAL_FAILED)); rb_define_const(eXMLError, "XPTR_EXTRA_OBJECTS", INT2NUM(XML_XPTR_EXTRA_OBJECTS)); rb_define_const(eXMLError, "C14N_CREATE_CTXT", INT2NUM(XML_C14N_CREATE_CTXT)); rb_define_const(eXMLError, "C14N_REQUIRES_UTF8", INT2NUM(XML_C14N_REQUIRES_UTF8)); rb_define_const(eXMLError, "C14N_CREATE_STACK", INT2NUM(XML_C14N_CREATE_STACK)); rb_define_const(eXMLError, "C14N_INVALID_NODE", INT2NUM(XML_C14N_INVALID_NODE)); #if LIBXML_VERSION >= 20619 rb_define_const(eXMLError, "C14N_UNKNOW_NODE", INT2NUM(XML_C14N_UNKNOW_NODE)); rb_define_const(eXMLError, "C14N_RELATIVE_NAMESPACE", INT2NUM(XML_C14N_RELATIVE_NAMESPACE)); #endif rb_define_const(eXMLError, "FTP_PASV_ANSWER", INT2NUM(XML_FTP_PASV_ANSWER)); rb_define_const(eXMLError, "FTP_EPSV_ANSWER", INT2NUM(XML_FTP_EPSV_ANSWER)); rb_define_const(eXMLError, "FTP_ACCNT", INT2NUM(XML_FTP_ACCNT)); #if LIBXML_VERSION >= 20618 rb_define_const(eXMLError, "FTP_URL_SYNTAX", INT2NUM(XML_FTP_URL_SYNTAX)); #endif rb_define_const(eXMLError, "HTTP_URL_SYNTAX", INT2NUM(XML_HTTP_URL_SYNTAX)); rb_define_const(eXMLError, "HTTP_USE_IP", INT2NUM(XML_HTTP_USE_IP)); rb_define_const(eXMLError, "HTTP_UNKNOWN_HOST", INT2NUM(XML_HTTP_UNKNOWN_HOST)); rb_define_const(eXMLError, "SCHEMAP_SRC_SIMPLE_TYPE_1", INT2NUM(XML_SCHEMAP_SRC_SIMPLE_TYPE_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_SIMPLE_TYPE_2", INT2NUM(XML_SCHEMAP_SRC_SIMPLE_TYPE_2)); rb_define_const(eXMLError, "SCHEMAP_SRC_SIMPLE_TYPE_3", INT2NUM(XML_SCHEMAP_SRC_SIMPLE_TYPE_3)); rb_define_const(eXMLError, "SCHEMAP_SRC_SIMPLE_TYPE_4", INT2NUM(XML_SCHEMAP_SRC_SIMPLE_TYPE_4)); rb_define_const(eXMLError, "SCHEMAP_SRC_RESOLVE", INT2NUM(XML_SCHEMAP_SRC_RESOLVE)); rb_define_const(eXMLError, "SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE", INT2NUM(XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE)); rb_define_const(eXMLError, "SCHEMAP_SRC_LIST_ITEMTYPE_OR_SIMPLETYPE", INT2NUM(XML_SCHEMAP_SRC_LIST_ITEMTYPE_OR_SIMPLETYPE)); rb_define_const(eXMLError, "SCHEMAP_SRC_UNION_MEMBERTYPES_OR_SIMPLETYPES", INT2NUM(XML_SCHEMAP_SRC_UNION_MEMBERTYPES_OR_SIMPLETYPES)); rb_define_const(eXMLError, "SCHEMAP_ST_PROPS_CORRECT_1", INT2NUM(XML_SCHEMAP_ST_PROPS_CORRECT_1)); rb_define_const(eXMLError, "SCHEMAP_ST_PROPS_CORRECT_2", INT2NUM(XML_SCHEMAP_ST_PROPS_CORRECT_2)); rb_define_const(eXMLError, "SCHEMAP_ST_PROPS_CORRECT_3", INT2NUM(XML_SCHEMAP_ST_PROPS_CORRECT_3)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_1_1", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_1_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_1_2", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_1_2)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_1_3_1", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_1_3_2", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_1_3_2)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_2_1", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_2_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_2_3_1_1", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_2_3_1_2", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_2_3_2_1", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_2_3_2_2", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_2_3_2_3", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_2_3_2_4", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_2_3_2_5", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_5)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_3_1", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_3_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_3_3_1", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_3_3_1_2", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_3_3_2_2", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_3_3_2_1", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_3_3_2_3", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_3_3_2_4", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_RESTRICTS_3_3_2_5", INT2NUM(XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_5)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_DERIVED_OK_2_1", INT2NUM(XML_SCHEMAP_COS_ST_DERIVED_OK_2_1)); rb_define_const(eXMLError, "SCHEMAP_COS_ST_DERIVED_OK_2_2", INT2NUM(XML_SCHEMAP_COS_ST_DERIVED_OK_2_2)); rb_define_const(eXMLError, "SCHEMAP_S4S_ELEM_NOT_ALLOWED", INT2NUM(XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED)); rb_define_const(eXMLError, "SCHEMAP_S4S_ELEM_MISSING", INT2NUM(XML_SCHEMAP_S4S_ELEM_MISSING)); rb_define_const(eXMLError, "SCHEMAP_S4S_ATTR_NOT_ALLOWED", INT2NUM(XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED)); rb_define_const(eXMLError, "SCHEMAP_S4S_ATTR_MISSING", INT2NUM(XML_SCHEMAP_S4S_ATTR_MISSING)); rb_define_const(eXMLError, "SCHEMAP_S4S_ATTR_INVALID_VALUE", INT2NUM(XML_SCHEMAP_S4S_ATTR_INVALID_VALUE)); rb_define_const(eXMLError, "SCHEMAP_SRC_ELEMENT_1", INT2NUM(XML_SCHEMAP_SRC_ELEMENT_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_ELEMENT_2_1", INT2NUM(XML_SCHEMAP_SRC_ELEMENT_2_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_ELEMENT_2_2", INT2NUM(XML_SCHEMAP_SRC_ELEMENT_2_2)); rb_define_const(eXMLError, "SCHEMAP_SRC_ELEMENT_3", INT2NUM(XML_SCHEMAP_SRC_ELEMENT_3)); rb_define_const(eXMLError, "SCHEMAP_P_PROPS_CORRECT_1", INT2NUM(XML_SCHEMAP_P_PROPS_CORRECT_1)); rb_define_const(eXMLError, "SCHEMAP_P_PROPS_CORRECT_2_1", INT2NUM(XML_SCHEMAP_P_PROPS_CORRECT_2_1)); rb_define_const(eXMLError, "SCHEMAP_P_PROPS_CORRECT_2_2", INT2NUM(XML_SCHEMAP_P_PROPS_CORRECT_2_2)); rb_define_const(eXMLError, "SCHEMAP_E_PROPS_CORRECT_2", INT2NUM(XML_SCHEMAP_E_PROPS_CORRECT_2)); rb_define_const(eXMLError, "SCHEMAP_E_PROPS_CORRECT_3", INT2NUM(XML_SCHEMAP_E_PROPS_CORRECT_3)); rb_define_const(eXMLError, "SCHEMAP_E_PROPS_CORRECT_4", INT2NUM(XML_SCHEMAP_E_PROPS_CORRECT_4)); rb_define_const(eXMLError, "SCHEMAP_E_PROPS_CORRECT_5", INT2NUM(XML_SCHEMAP_E_PROPS_CORRECT_5)); rb_define_const(eXMLError, "SCHEMAP_E_PROPS_CORRECT_6", INT2NUM(XML_SCHEMAP_E_PROPS_CORRECT_6)); rb_define_const(eXMLError, "SCHEMAP_SRC_INCLUDE", INT2NUM(XML_SCHEMAP_SRC_INCLUDE)); rb_define_const(eXMLError, "SCHEMAP_SRC_ATTRIBUTE_1", INT2NUM(XML_SCHEMAP_SRC_ATTRIBUTE_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_ATTRIBUTE_2", INT2NUM(XML_SCHEMAP_SRC_ATTRIBUTE_2)); rb_define_const(eXMLError, "SCHEMAP_SRC_ATTRIBUTE_3_1", INT2NUM(XML_SCHEMAP_SRC_ATTRIBUTE_3_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_ATTRIBUTE_3_2", INT2NUM(XML_SCHEMAP_SRC_ATTRIBUTE_3_2)); rb_define_const(eXMLError, "SCHEMAP_SRC_ATTRIBUTE_4", INT2NUM(XML_SCHEMAP_SRC_ATTRIBUTE_4)); rb_define_const(eXMLError, "SCHEMAP_NO_XMLNS", INT2NUM(XML_SCHEMAP_NO_XMLNS)); rb_define_const(eXMLError, "SCHEMAP_NO_XSI", INT2NUM(XML_SCHEMAP_NO_XSI)); rb_define_const(eXMLError, "SCHEMAP_COS_VALID_DEFAULT_1", INT2NUM(XML_SCHEMAP_COS_VALID_DEFAULT_1)); rb_define_const(eXMLError, "SCHEMAP_COS_VALID_DEFAULT_2_1", INT2NUM(XML_SCHEMAP_COS_VALID_DEFAULT_2_1)); rb_define_const(eXMLError, "SCHEMAP_COS_VALID_DEFAULT_2_2_1", INT2NUM(XML_SCHEMAP_COS_VALID_DEFAULT_2_2_1)); rb_define_const(eXMLError, "SCHEMAP_COS_VALID_DEFAULT_2_2_2", INT2NUM(XML_SCHEMAP_COS_VALID_DEFAULT_2_2_2)); rb_define_const(eXMLError, "SCHEMAP_CVC_SIMPLE_TYPE", INT2NUM(XML_SCHEMAP_CVC_SIMPLE_TYPE)); rb_define_const(eXMLError, "SCHEMAP_COS_CT_EXTENDS_1_1", INT2NUM(XML_SCHEMAP_COS_CT_EXTENDS_1_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_IMPORT_1_1", INT2NUM(XML_SCHEMAP_SRC_IMPORT_1_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_IMPORT_1_2", INT2NUM(XML_SCHEMAP_SRC_IMPORT_1_2)); rb_define_const(eXMLError, "SCHEMAP_SRC_IMPORT_2", INT2NUM(XML_SCHEMAP_SRC_IMPORT_2)); rb_define_const(eXMLError, "SCHEMAP_SRC_IMPORT_2_1", INT2NUM(XML_SCHEMAP_SRC_IMPORT_2_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_IMPORT_2_2", INT2NUM(XML_SCHEMAP_SRC_IMPORT_2_2)); rb_define_const(eXMLError, "SCHEMAP_INTERNAL", INT2NUM(XML_SCHEMAP_INTERNAL)); rb_define_const(eXMLError, "SCHEMAP_NOT_DETERMINISTIC", INT2NUM(XML_SCHEMAP_NOT_DETERMINISTIC)); rb_define_const(eXMLError, "SCHEMAP_SRC_ATTRIBUTE_GROUP_1", INT2NUM(XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_1)); rb_define_const(eXMLError, "SCHEMAP_SRC_ATTRIBUTE_GROUP_2", INT2NUM(XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_2)); rb_define_const(eXMLError, "SCHEMAP_SRC_ATTRIBUTE_GROUP_3", INT2NUM(XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_3)); rb_define_const(eXMLError, "SCHEMAP_MG_PROPS_CORRECT_1", INT2NUM(XML_SCHEMAP_MG_PROPS_CORRECT_1)); rb_define_const(eXMLError, "SCHEMAP_MG_PROPS_CORRECT_2", INT2NUM(XML_SCHEMAP_MG_PROPS_CORRECT_2)); rb_define_const(eXMLError, "SCHEMAP_SRC_CT_1", INT2NUM(XML_SCHEMAP_SRC_CT_1)); rb_define_const(eXMLError, "SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_3", INT2NUM(XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_3)); rb_define_const(eXMLError, "SCHEMAP_AU_PROPS_CORRECT_2", INT2NUM(XML_SCHEMAP_AU_PROPS_CORRECT_2)); rb_define_const(eXMLError, "SCHEMAP_A_PROPS_CORRECT_2", INT2NUM(XML_SCHEMAP_A_PROPS_CORRECT_2)); #if LIBXML_VERSION >= 20620 rb_define_const(eXMLError, "SCHEMAP_C_PROPS_CORRECT", INT2NUM(XML_SCHEMAP_C_PROPS_CORRECT)); #endif #if LIBXML_VERSION >= 20621 rb_define_const(eXMLError, "SCHEMAP_SRC_REDEFINE", INT2NUM(XML_SCHEMAP_SRC_REDEFINE)); rb_define_const(eXMLError, "SCHEMAP_SRC_IMPORT", INT2NUM(XML_SCHEMAP_SRC_IMPORT)); rb_define_const(eXMLError, "SCHEMAP_WARN_SKIP_SCHEMA", INT2NUM(XML_SCHEMAP_WARN_SKIP_SCHEMA)); rb_define_const(eXMLError, "SCHEMAP_WARN_UNLOCATED_SCHEMA", INT2NUM(XML_SCHEMAP_WARN_UNLOCATED_SCHEMA)); rb_define_const(eXMLError, "SCHEMAP_WARN_ATTR_REDECL_PROH", INT2NUM(XML_SCHEMAP_WARN_ATTR_REDECL_PROH)); rb_define_const(eXMLError, "SCHEMAP_WARN_ATTR_POINTLESS_PROH", INT2NUM(XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH)); #endif #if LIBXML_VERSION >= 20623 rb_define_const(eXMLError, "SCHEMAP_AG_PROPS_CORRECT", INT2NUM(XML_SCHEMAP_AG_PROPS_CORRECT)); rb_define_const(eXMLError, "SCHEMAP_COS_CT_EXTENDS_1_2", INT2NUM(XML_SCHEMAP_COS_CT_EXTENDS_1_2)); rb_define_const(eXMLError, "SCHEMAP_AU_PROPS_CORRECT", INT2NUM(XML_SCHEMAP_AU_PROPS_CORRECT)); rb_define_const(eXMLError, "SCHEMAP_A_PROPS_CORRECT_3", INT2NUM(XML_SCHEMAP_A_PROPS_CORRECT_3)); rb_define_const(eXMLError, "SCHEMAP_COS_ALL_LIMITED", INT2NUM(XML_SCHEMAP_COS_ALL_LIMITED)); #endif #if LIBXML_VERSION >= 20632 rb_define_const(eXMLError, "SCHEMATRONV_ASSERT", INT2NUM(XML_SCHEMATRONV_ASSERT)); rb_define_const(eXMLError, "SCHEMATRONV_REPORT", INT2NUM(XML_SCHEMATRONV_REPORT)); #endif #if LIBXML_VERSION >= 20618 rb_define_const(eXMLError, "MODULE_OPEN", INT2NUM(XML_MODULE_OPEN)); rb_define_const(eXMLError, "MODULE_CLOSE", INT2NUM(XML_MODULE_CLOSE)); #endif rb_define_const(eXMLError, "CHECK_FOUND_ELEMENT", INT2NUM(XML_CHECK_FOUND_ELEMENT)); rb_define_const(eXMLError, "CHECK_FOUND_ATTRIBUTE", INT2NUM(XML_CHECK_FOUND_ATTRIBUTE)); rb_define_const(eXMLError, "CHECK_FOUND_TEXT", INT2NUM(XML_CHECK_FOUND_TEXT)); rb_define_const(eXMLError, "CHECK_FOUND_CDATA",INT2NUM(XML_CHECK_FOUND_CDATA)); rb_define_const(eXMLError, "CHECK_FOUND_ENTITYREF", INT2NUM(XML_CHECK_FOUND_ENTITYREF)); rb_define_const(eXMLError, "CHECK_FOUND_ENTITY", INT2NUM(XML_CHECK_FOUND_ENTITY)); rb_define_const(eXMLError, "CHECK_FOUND_PI", INT2NUM(XML_CHECK_FOUND_PI)); rb_define_const(eXMLError, "CHECK_FOUND_COMMENT", INT2NUM(XML_CHECK_FOUND_COMMENT)); rb_define_const(eXMLError, "CHECK_FOUND_DOCTYPE", INT2NUM(XML_CHECK_FOUND_DOCTYPE)); rb_define_const(eXMLError, "CHECK_FOUND_FRAGMENT", INT2NUM(XML_CHECK_FOUND_FRAGMENT)); rb_define_const(eXMLError, "CHECK_FOUND_NOTATION", INT2NUM(XML_CHECK_FOUND_NOTATION)); rb_define_const(eXMLError, "CHECK_UNKNOWN_NODE", INT2NUM(XML_CHECK_UNKNOWN_NODE)); rb_define_const(eXMLError, "CHECK_ENTITY_TYPE", INT2NUM(XML_CHECK_ENTITY_TYPE)); rb_define_const(eXMLError, "CHECK_NO_PARENT", INT2NUM(XML_CHECK_NO_PARENT)); rb_define_const(eXMLError, "CHECK_NO_DOC", INT2NUM(XML_CHECK_NO_DOC)); rb_define_const(eXMLError, "CHECK_NO_NAME", INT2NUM(XML_CHECK_NO_NAME)); rb_define_const(eXMLError, "CHECK_NO_ELEM", INT2NUM(XML_CHECK_NO_ELEM)); rb_define_const(eXMLError, "CHECK_WRONG_DOC", INT2NUM(XML_CHECK_WRONG_DOC)); rb_define_const(eXMLError, "CHECK_NO_PREV", INT2NUM(XML_CHECK_NO_PREV)); rb_define_const(eXMLError, "CHECK_WRONG_PREV", INT2NUM(XML_CHECK_WRONG_PREV)); rb_define_const(eXMLError, "CHECK_NO_NEXT", INT2NUM(XML_CHECK_NO_NEXT)); rb_define_const(eXMLError, "CHECK_WRONG_NEXT", INT2NUM(XML_CHECK_WRONG_NEXT)); rb_define_const(eXMLError, "CHECK_NOT_DTD", INT2NUM(XML_CHECK_NOT_DTD)); rb_define_const(eXMLError, "CHECK_NOT_ATTR", INT2NUM(XML_CHECK_NOT_ATTR)); rb_define_const(eXMLError, "CHECK_NOT_ATTR_DECL", INT2NUM(XML_CHECK_NOT_ATTR_DECL)); rb_define_const(eXMLError, "CHECK_NOT_ELEM_DECL", INT2NUM(XML_CHECK_NOT_ELEM_DECL)); rb_define_const(eXMLError, "CHECK_NOT_ENTITY_DECL", INT2NUM(XML_CHECK_NOT_ENTITY_DECL)); rb_define_const(eXMLError, "CHECK_NOT_NS_DECL", INT2NUM(XML_CHECK_NOT_NS_DECL)); rb_define_const(eXMLError, "CHECK_NO_HREF", INT2NUM(XML_CHECK_NO_HREF)); rb_define_const(eXMLError, "CHECK_WRONG_PARENT", INT2NUM(XML_CHECK_WRONG_PARENT)); rb_define_const(eXMLError, "CHECK_NS_SCOPE", INT2NUM(XML_CHECK_NS_SCOPE)); rb_define_const(eXMLError, "CHECK_NS_ANCESTOR", INT2NUM(XML_CHECK_NS_ANCESTOR)); rb_define_const(eXMLError, "CHECK_NOT_UTF8", INT2NUM(XML_CHECK_NOT_UTF8)); rb_define_const(eXMLError, "CHECK_NO_DICT", INT2NUM(XML_CHECK_NO_DICT)); rb_define_const(eXMLError, "CHECK_NOT_NCNAME", INT2NUM(XML_CHECK_NOT_NCNAME)); rb_define_const(eXMLError, "CHECK_OUTSIDE_DICT", INT2NUM(XML_CHECK_OUTSIDE_DICT)); rb_define_const(eXMLError, "CHECK_WRONG_NAME", INT2NUM(XML_CHECK_WRONG_NAME)); #if LIBXML_VERSION >= 20621 rb_define_const(eXMLError, "CHECK_NAME_NOT_NULL", INT2NUM(XML_CHECK_NAME_NOT_NULL)); rb_define_const(eXMLError, "I18N_NO_NAME", INT2NUM(XML_I18N_NO_NAME)); rb_define_const(eXMLError, "I18N_NO_HANDLER", INT2NUM(XML_I18N_NO_HANDLER)); rb_define_const(eXMLError, "I18N_EXCESS_HANDLER", INT2NUM(XML_I18N_EXCESS_HANDLER)); rb_define_const(eXMLError, "I18N_CONV_FAILED", INT2NUM(XML_I18N_CONV_FAILED)); rb_define_const(eXMLError, "I18N_NO_OUTPUT", INT2NUM(XML_I18N_NO_OUTPUT)); #endif } libxml-ruby-5.0.3/ext/libxml/extconf.h0000644000004100000410000000005314620142101017710 0ustar www-datawww-data#ifndef EXTCONF_H #define EXTCONF_H #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_sax2_handler.c0000644000004100000410000002273414620142101022542 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_sax2_handler.h" VALUE cbidOnCdataBlock; VALUE cbidOnCharacters; VALUE cbidOnComment; VALUE cbidOnEndDocument; VALUE cbidOnEndElement; VALUE cbidOnEndElementNs; VALUE cbidOnExternalSubset; VALUE cbidOnHasExternalSubset; VALUE cbidOnHasInternalSubset; VALUE cbidOnInternalSubset; VALUE cbidOnIsStandalone; VALUE cbidOnError; VALUE cbidOnProcessingInstruction; VALUE cbidOnReference; VALUE cbidOnStartElement; VALUE cbidOnStartElementNs; VALUE cbidOnStartDocument; /* ====== Callbacks =========== */ static void cdata_block_callback(void *ctx, const xmlChar *value, int len) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { rb_funcall(handler, cbidOnCdataBlock,1, rxml_new_cstr_len(value, len, NULL)); } } static void characters_callback(void *ctx, const xmlChar *chars, int len) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { VALUE rchars = rxml_new_cstr_len(chars, len, NULL); rb_funcall(handler, cbidOnCharacters, 1, rchars); } } static void comment_callback(void *ctx, const xmlChar *msg) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { rb_funcall(handler, cbidOnComment, 1, rxml_new_cstr(msg, NULL)); } } static void end_document_callback(void *ctx) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { rb_funcall(handler, cbidOnEndDocument, 0); } } static void end_element_ns_callback(void *ctx, const xmlChar *xlocalname, const xmlChar *xprefix, const xmlChar *xURI) { VALUE handler = (VALUE) ctx; if (handler == Qnil) return; /* Call end element for old-times sake */ if (rb_respond_to(handler, cbidOnEndElement)) { VALUE name; if (xprefix) { name = rxml_new_cstr(xprefix, NULL); rb_str_cat2(name, ":"); rb_str_cat2(name, (const char*)xlocalname); } else { name = rxml_new_cstr(xlocalname, NULL); } rb_funcall(handler, cbidOnEndElement, 1, name); } rb_funcall(handler, cbidOnEndElementNs, 3, rxml_new_cstr(xlocalname, NULL), xprefix ? rxml_new_cstr(xprefix, NULL) : Qnil, xURI ? rxml_new_cstr(xURI, NULL) : Qnil); } static void external_subset_callback(void *ctx, const xmlChar *name, const xmlChar *extid, const xmlChar *sysid) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { VALUE rname = name ? rxml_new_cstr(name, NULL) : Qnil; VALUE rextid = extid ? rxml_new_cstr(extid, NULL) : Qnil; VALUE rsysid = sysid ? rxml_new_cstr(sysid, NULL) : Qnil; rb_funcall(handler, cbidOnExternalSubset, 3, rname, rextid, rsysid); } } static void has_external_subset_callback(void *ctx) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { rb_funcall(handler, cbidOnHasExternalSubset, 0); } } static void has_internal_subset_callback(void *ctx) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { rb_funcall(handler, cbidOnHasInternalSubset, 0); } } static void internal_subset_callback(void *ctx, const xmlChar *name, const xmlChar *extid, const xmlChar *sysid) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { VALUE rname = name ? rxml_new_cstr(name, NULL) : Qnil; VALUE rextid = extid ? rxml_new_cstr(extid, NULL) : Qnil; VALUE rsysid = sysid ? rxml_new_cstr(sysid, NULL) : Qnil; rb_funcall(handler, cbidOnInternalSubset, 3, rname, rextid, rsysid); } } static void is_standalone_callback(void *ctx) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { rb_funcall(handler, cbidOnIsStandalone,0); } } static void processing_instruction_callback(void *ctx, const xmlChar *target, const xmlChar *data) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { VALUE rtarget = target ? rxml_new_cstr(target, NULL) : Qnil; VALUE rdata = data ? rxml_new_cstr(data, NULL) : Qnil; rb_funcall(handler, cbidOnProcessingInstruction, 2, rtarget, rdata); } } static void reference_callback(void *ctx, const xmlChar *name) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { rb_funcall(handler, cbidOnReference, 1, rxml_new_cstr(name, NULL)); } } static void start_document_callback(void *ctx) { VALUE handler = (VALUE) ctx; if (handler != Qnil) { rb_funcall(handler, cbidOnStartDocument, 0); } } static void start_element_ns_callback(void *ctx, const xmlChar *xlocalname, const xmlChar *xprefix, const xmlChar *xURI, int nb_namespaces, const xmlChar **xnamespaces, int nb_attributes, int nb_defaulted, const xmlChar **xattributes) { VALUE handler = (VALUE) ctx; VALUE attributes = rb_hash_new(); VALUE namespaces = rb_hash_new(); if (handler == Qnil) return; if (xattributes) { /* Each attribute is an array of [localname, prefix, URI, value, end] */ int i; for (i = 0;i < nb_attributes * 5; i+=5) { VALUE attrName = rxml_new_cstr(xattributes[i+0], NULL); long attrLen = (long)(xattributes[i+4] - xattributes[i+3]); VALUE attrValue = rxml_new_cstr_len(xattributes[i+3], attrLen, NULL); rb_hash_aset(attributes, attrName, attrValue); } } if (xnamespaces) { int i; for (i = 0;i < nb_namespaces * 2; i+=2) { VALUE nsPrefix = xnamespaces[i+0] ? rxml_new_cstr(xnamespaces[i+0], NULL) : Qnil; VALUE nsURI = xnamespaces[i+1] ? rxml_new_cstr(xnamespaces[i+1], NULL) : Qnil; rb_hash_aset(namespaces, nsPrefix, nsURI); } } /* Call start element for old-times sake */ if (rb_respond_to(handler, cbidOnStartElement)) { VALUE name; if (xprefix) { name = rxml_new_cstr(xprefix, NULL); rb_str_cat2(name, ":"); rb_str_cat2(name, (const char*)xlocalname); } else { name = rxml_new_cstr(xlocalname, NULL); } rb_funcall(handler, cbidOnStartElement, 2, name, attributes); } rb_funcall(handler, cbidOnStartElementNs, 5, rxml_new_cstr(xlocalname, NULL), attributes, xprefix ? rxml_new_cstr(xprefix, NULL) : Qnil, xURI ? rxml_new_cstr(xURI, NULL) : Qnil, namespaces); } static void structured_error_callback(void *ctx, const xmlError *xerror) { /* Older versions of Libxml will pass a NULL context from the sax parser. Fixed on Feb 23, 2011. See: http://git.gnome.org/browse/libxml2/commit/?id=241d4a1069e6bedd0ee2295d7b43858109c1c6d1 */ VALUE handler; #if LIBXML_VERSION <= 20708 xmlParserCtxtPtr ctxt = (xmlParserCtxt*)(xerror->ctxt); ctx = ctxt->userData; #endif handler = (VALUE) ctx; if (handler != Qnil) { VALUE error = rxml_error_wrap(xerror); rb_funcall(handler, cbidOnError, 1, error); } } /* ====== Handler =========== */ xmlSAXHandler rxml_sax_handler = { (internalSubsetSAXFunc) internal_subset_callback, (isStandaloneSAXFunc) is_standalone_callback, (hasInternalSubsetSAXFunc) has_internal_subset_callback, (hasExternalSubsetSAXFunc) has_external_subset_callback, 0, /* resolveEntity */ 0, /* getEntity */ 0, /* entityDecl */ 0, /* notationDecl */ 0, /* attributeDecl */ 0, /* elementDecl */ 0, /* unparsedEntityDecl */ 0, /* setDocumentLocator */ (startDocumentSAXFunc) start_document_callback, (endDocumentSAXFunc) end_document_callback, 0, /* Use start_element_ns_callback instead */ 0, /* Use end_element_ns_callback instead */ (referenceSAXFunc) reference_callback, (charactersSAXFunc) characters_callback, 0, /* ignorableWhitespace */ (processingInstructionSAXFunc) processing_instruction_callback, (commentSAXFunc) comment_callback, 0, /* xmlStructuredErrorFunc is used instead */ 0, /* xmlStructuredErrorFunc is used instead */ 0, /* xmlStructuredErrorFunc is used instead */ 0, /* xmlGetParameterEntity */ (cdataBlockSAXFunc) cdata_block_callback, (externalSubsetSAXFunc) external_subset_callback, XML_SAX2_MAGIC, /* force SAX2 */ 0, /* _private */ (startElementNsSAX2Func) start_element_ns_callback, (endElementNsSAX2Func) end_element_ns_callback, (xmlStructuredErrorFunc) structured_error_callback }; void rxml_init_sax2_handler(void) { /* SaxCallbacks */ cbidOnCdataBlock = rb_intern("on_cdata_block"); cbidOnCharacters = rb_intern("on_characters"); cbidOnComment = rb_intern("on_comment"); cbidOnEndDocument = rb_intern("on_end_document"); cbidOnEndElement = rb_intern("on_end_element"); cbidOnEndElementNs = rb_intern("on_end_element_ns"); cbidOnError = rb_intern("on_error"); cbidOnExternalSubset = rb_intern("on_external_subset"); cbidOnHasExternalSubset = rb_intern("on_has_external_subset"); cbidOnHasInternalSubset = rb_intern("on_has_internal_subset"); cbidOnInternalSubset = rb_intern("on_internal_subset"); cbidOnIsStandalone = rb_intern("on_is_standalone"); cbidOnProcessingInstruction = rb_intern("on_processing_instruction"); cbidOnReference = rb_intern("on_reference"); cbidOnStartElement = rb_intern("on_start_element"); cbidOnStartElementNs = rb_intern("on_start_element_ns"); cbidOnStartDocument = rb_intern("on_start_document"); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_html_parser.h0000644000004100000410000000033314620142101022504 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_HTML_PARSER__ #define __RXML_HTML_PARSER__ extern VALUE cXMLHtmlParser; void rxml_init_html_parser(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_html_parser_context.h0000644000004100000410000000037214620142101024253 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_HTML_PARSER_CONTEXT__ #define __RXML_HTML_PARSER_CONTEXT__ extern VALUE cXMLHtmlParserContext; void rxml_init_html_parser_context(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_namespaces.h0000644000004100000410000000032614620142101022305 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_NAMESPACES__ #define __RXML_NAMESPACES__ extern VALUE cXMLNamespaces; void rxml_init_namespaces(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_html_parser.c0000644000004100000410000000500414620142101022477 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include /* Document-class: LibXML::XML::HTMLParser * * The HTML parser implements an HTML 4.0 non-verifying parser with an API * compatible with the XML::Parser. In contrast with the XML::Parser, * it can parse "real world" HTML, even if it severely broken from a * specification point of view. * * The HTML parser creates an in-memory document object * that consist of any number of XML::Node instances. This is simple * and powerful model, but has the major limitation that the size of * the document that can be processed is limited by the amount of * memory available. * * Using the html parser is simple: * * parser = XML::HTMLParser.file('my_file') * doc = parser.parse * * You can also parse documents (see XML::HTMLParser.document), * strings (see XML::HTMLParser.string) and io objects (see * XML::HTMLParser.io). */ VALUE cXMLHtmlParser; static ID CONTEXT_ATTR; /* call-seq: * XML::HTMLParser.initialize -> parser * * Initializes a new parser instance with no pre-determined source. */ static VALUE rxml_html_parser_initialize(int argc, VALUE *argv, VALUE self) { VALUE context = Qnil; rb_scan_args(argc, argv, "01", &context); if (context == Qnil) { rb_raise(rb_eArgError, "An instance of a XML::Parser::Context must be passed to XML::HTMLParser.new"); } rb_ivar_set(self, CONTEXT_ATTR, context); return self; } /* * call-seq: * parser.parse -> XML::Document * * Parse the input XML and create an XML::Document with * it's content. If an error occurs, XML::Parser::ParseError * is thrown. */ static VALUE rxml_html_parser_parse(VALUE self) { xmlParserCtxtPtr ctxt; VALUE context = rb_ivar_get(self, CONTEXT_ATTR); Data_Get_Struct(context, xmlParserCtxt, ctxt); if (htmlParseDocument(ctxt) == -1 && ! ctxt->recovery) { rxml_raise(&ctxt->lastError); } rb_funcall(context, rb_intern("close"), 0); return rxml_document_wrap(ctxt->myDoc); } void rxml_init_html_parser(void) { CONTEXT_ATTR = rb_intern("@context"); cXMLHtmlParser = rb_define_class_under(mXML, "HTMLParser", rb_cObject); /* Atributes */ rb_define_attr(cXMLHtmlParser, "input", 1, 0); /* Instance methods */ rb_define_method(cXMLHtmlParser, "initialize", rxml_html_parser_initialize, -1); rb_define_method(cXMLHtmlParser, "parse", rxml_html_parser_parse, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_sax_parser.h0000644000004100000410000000032714620142101022336 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_SAX_PARSER__ #define __RXML_SAX_PARSER__ extern VALUE cXMLSaxParser; void rxml_init_sax_parser(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema_type.h0000644000004100000410000000030114620142101022460 0ustar www-datawww-data#ifndef __RXML_SCHEMA_TYPE__ #define __RXML_SCHEMA_TYPE__ extern VALUE cXMLSchemaType; VALUE rxml_wrap_schema_type(xmlSchemaTypePtr xtype); void rxml_init_schema_type(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_libxml.h0000644000004100000410000000225214620142101020575 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RUBY_LIBXML_H__ #define __RUBY_LIBXML_H__ #include #include "ruby_xml_version.h" #include "ruby_xml.h" #include "ruby_xml_io.h" #include "ruby_xml_error.h" #include "ruby_xml_encoding.h" #include "ruby_xml_attributes.h" #include "ruby_xml_attr.h" #include "ruby_xml_attr_decl.h" #include "ruby_xml_document.h" #include "ruby_xml_node.h" #include "ruby_xml_namespace.h" #include "ruby_xml_namespaces.h" #include "ruby_xml_parser.h" #include "ruby_xml_parser_options.h" #include "ruby_xml_parser_context.h" #include "ruby_xml_html_parser.h" #include "ruby_xml_html_parser_options.h" #include "ruby_xml_html_parser_context.h" #include "ruby_xml_reader.h" #include "ruby_xml_writer.h" #include "ruby_xml_sax2_handler.h" #include "ruby_xml_sax_parser.h" #include "ruby_xml_writer.h" #include "ruby_xml_xinclude.h" #include "ruby_xml_xpath.h" #include "ruby_xml_xpath_expression.h" #include "ruby_xml_xpath_context.h" #include "ruby_xml_xpath_object.h" #include "ruby_xml_input_cbg.h" #include "ruby_xml_dtd.h" #include "ruby_xml_schema.h" #include "ruby_xml_relaxng.h" extern VALUE mLibXML; #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_xinclude.c0000644000004100000410000000062214620142101021773 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_xinclude.h" #ifdef LIBXML_XINCLUDE_ENABLED #include #endif VALUE cXMLXInclude; /* * Document-class: LibXML::XML::XInclude * * The ruby bindings do not currently expose libxml's * XInclude fuctionality. */ void rxml_init_xinclude(void) { cXMLXInclude = rb_define_class_under(mXML, "XInclude", rb_cObject); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_html_parser_options.c0000644000004100000410000000356614620142101024265 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include /* Document-class: LibXML::XML::HTMLParser::Options * * Options to control the operation of the HTMLParser. The easiest * way to set a parser's options is via the methods * XML::HTMLParser.file, XML::HTMLParser.io or XML::HTMLParser.string. * For additional control, see XML::HTMLParser::Context#options=. */ VALUE mXMLHtmlParserOptions; void rxml_init_html_parser_options(void) { mXMLHtmlParserOptions = rb_define_module_under(cXMLHtmlParser, "Options"); #if LIBXML_VERSION >= 20621 /* 1: Relax parsing. */ rb_define_const(mXMLHtmlParserOptions, "RECOVER", INT2NUM(HTML_PARSE_RECOVER)); #endif #if LIBXML_VERSION >= 20708 /* 2: Do not default a doctype if not found */ rb_define_const(mXMLHtmlParserOptions, "NODEFDTD", INT2NUM(HTML_PARSE_NODEFDTD)); #endif /* 32: Suppress error reports. */ rb_define_const(mXMLHtmlParserOptions, "NOERROR", INT2NUM(HTML_PARSE_NOERROR)); /* 64: Suppress warning reports. */ rb_define_const(mXMLHtmlParserOptions, "NOWARNING", INT2NUM(HTML_PARSE_NOWARNING)); /* 128: Enable pedantic error reporting. */ rb_define_const(mXMLHtmlParserOptions, "PEDANTIC", INT2NUM(HTML_PARSE_PEDANTIC)); /* 256: Remove blank nodes. */ rb_define_const(mXMLHtmlParserOptions, "NOBLANKS", INT2NUM(HTML_PARSE_NOBLANKS)); #if LIBXML_VERSION >= 20621 /* 2048: Forbid network access. */ rb_define_const(mXMLHtmlParserOptions, "NONET", INT2NUM(HTML_PARSE_NONET)); /* 65536: Compact small text nodes. */ rb_define_const(mXMLHtmlParserOptions, "COMPACT", INT2NUM(HTML_PARSE_COMPACT)); #endif #if LIBXML_VERSION >= 20707 /* 8192: Do not add implied html/body... elements */ rb_define_const(mXMLHtmlParserOptions, "NOIMPLIED", INT2NUM(HTML_PARSE_NOIMPLIED)); #endif } libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema_element.c0000644000004100000410000000362414620142101023136 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_schema_element.h" #include "ruby_xml_schema_type.h" VALUE cXMLSchemaElement; static void rxml_schema_element_free(xmlSchemaElementPtr xschema_element) { xschema_element = NULL; xmlFree(xschema_element); } VALUE rxml_wrap_schema_element(xmlSchemaElementPtr xelem) { VALUE result; if (!xelem) rb_raise(rb_eArgError, "XML::Schema::Element is required!"); result = Data_Wrap_Struct(cXMLSchemaElement, NULL, rxml_schema_element_free, xelem); rb_iv_set(result, "@name", QNIL_OR_STRING(xelem->name)); rb_iv_set(result, "@value", QNIL_OR_STRING(xelem->value)); rb_iv_set(result, "@namespace", QNIL_OR_STRING(xelem->targetNamespace)); rb_iv_set(result, "@type", rxml_wrap_schema_type((xmlSchemaTypePtr) (xelem->subtypes))); return result; } static VALUE rxml_schema_element_node(VALUE self) { xmlSchemaElementPtr xelem; Data_Get_Struct(self, xmlSchemaElement, xelem); return rxml_node_wrap(xelem->node); } static VALUE rxml_schema_element_annot(VALUE self) { xmlSchemaElementPtr xelem; VALUE annotation = Qnil; Data_Get_Struct(self, xmlSchemaElement, xelem); if ((xelem->annot != NULL) && (xelem->annot->content != NULL)) { xmlChar *content = xmlNodeGetContent(xelem->annot->content); if (content) { annotation = rxml_new_cstr(content, NULL); xmlFree(content); } } return annotation; } void rxml_init_schema_element(void) { cXMLSchemaElement = rb_define_class_under(cXMLSchema, "Element", rb_cObject); rb_undef_alloc_func(cXMLSchemaElement); rb_define_attr(cXMLSchemaElement, "name", 1, 0); rb_define_attr(cXMLSchemaElement, "value", 1, 0); rb_define_attr(cXMLSchemaElement, "namespace", 1, 0); rb_define_attr(cXMLSchemaElement, "type", 1, 0); rb_define_method(cXMLSchemaElement, "node", rxml_schema_element_node, 0); rb_define_method(cXMLSchemaElement, "annotation", rxml_schema_element_annot, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_io.h0000644000004100000410000000044014620142101020572 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_IO__ #define __RXML_IO__ int rxml_read_callback(void *context, char *buffer, int len); int rxml_write_callback(VALUE io, const char *buffer, int len); void rxml_init_io(void); #endif libxml-ruby-5.0.3/ext/libxml/libxml_ruby.def0000644000004100000410000000117614620142101021110 0ustar www-datawww-dataLIBRARY libxml_ruby.so EXPORTS Init_libxml_ruby rxml_document_wrap rxml_xpath_to_value rxml_xpath_from_value cXMLAttr DATA cXMLAttrDecl DATA cXMLAttributes DATA cXMLDocument DATA cXMLDtd DATA cXMLHtmlParser DATA cXMLHtmlParserContext DATA cXMLNamespace DATA cXMLNamespaces DATA cXMLNode DATA cXMLParser DATA cXMLParserContext DATA cXMLReader DATA cXMLRelaxNG DATA cXMLSaxParser DATA cXMLSchema DATA cXMLXInclude DATA cXMLXPathContext DATA cXMLXPathExpression DATA cXMLXPathObject DATA eXMLError DATA mLibXML DATA mXML DATA mXMLEncoding DATA mXMLHtmlParserOptions DATA mXMLParserOptions DATA mXPath DATA libxml-ruby-5.0.3/ext/libxml/ruby_xml_document.h0000644000004100000410000000041614620142101022004 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_DOCUMENT__ #define __RXML_DOCUMENT__ extern VALUE cXMLDocument; void rxml_init_document(void); VALUE rxml_document_wrap(xmlDocPtr xnode); typedef xmlChar * xmlCharPtr; #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_relaxng.h0000644000004100000410000000017514620142101021630 0ustar www-datawww-data#ifndef __RXML_RELAXNG__ #define __RXML_RELAXNG__ extern VALUE cXMLRelaxNG; void rxml_init_relaxng(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_xpath_object.h0000644000004100000410000000052514620142101022641 0ustar www-datawww-data#ifndef __RXML_XPATH_OBJECT__ #define __RXML_XPATH_OBJECT__ extern VALUE cXMLXPathObject; typedef struct rxml_xpath_object { xmlDocPtr xdoc; xmlXPathObjectPtr xpop; VALUE nsnodes; } rxml_xpath_object; void rxml_init_xpath_object(void); VALUE rxml_xpath_object_wrap(xmlDocPtr xdoc, xmlXPathObjectPtr xpop); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_attributes.c0000644000004100000410000001471414620142101022355 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ /* * Document-class: LibXML::XML::Attributes * * Provides access to an element's attributes (XML::Attr). * * Basic Usage: * require 'test_helper' * * doc = XML::Document.new() * attributes = doc.root.attributes * * attributes.each do |attribute| * .. * end * * attributes['foo'] = 'bar' * attribute = attributes.get_attribute['foo'] * attribute.value == 'foo' * * To access a namespaced attribute: * * XLINK_URI = 'http://www.w3.org/1999/xlink' * * attribute = attributes.get_attribute_ns(XLINK_URI, 'title') * attribute.value = 'My title' */ #include "ruby_libxml.h" #include "ruby_xml_attributes.h" VALUE cXMLAttributes; void rxml_attributes_mark(xmlNodePtr xnode) { rxml_node_mark(xnode); } /* * Creates a new attributes instance. Not exposed to ruby. */ VALUE rxml_attributes_new(xmlNodePtr xnode) { return Data_Wrap_Struct(cXMLAttributes, rxml_attributes_mark, NULL, xnode); } /* * call-seq: * attributes.node -> XML::Node * * Return the node that owns this attributes list. * * doc.root.attributes.node == doc.root */ VALUE rxml_attributes_node_get(VALUE self) { xmlNodePtr xnode; Data_Get_Struct(self, xmlNode, xnode); return rxml_node_wrap(xnode); } /* * call-seq: * attributes.get_attribute("name") -> (XML::Attr | XML::AtrrDecl) * * Returns the specified attribute. If the attribute does not * exist but the document has an associated DTD that defines * a default value for the attribute, then a XML::AttrDecl is * returned. * * name: The name of the attribute, not including a namespace. * * doc.root.attributes.get_attribute("foo") */ static VALUE rxml_attributes_get_attribute(VALUE self, VALUE name) { xmlNodePtr xnode; xmlAttrPtr xattr; name = rb_obj_as_string(name); Data_Get_Struct(self, xmlNode, xnode); xattr = xmlHasProp(xnode, (xmlChar*) StringValuePtr(name)); if (!xattr) return Qnil; else if (xattr->type == XML_ATTRIBUTE_DECL) return rxml_attr_decl_wrap((xmlAttributePtr)xattr); else return rxml_attr_wrap(xattr); } /* * call-seq: * attributes.get_attribute_ns("namespace", "name") -> (XML::Attr | XML::AtrrDecl) * * Returns the specified attribute. If the attribute does not * exist but the document has an associated DTD that defines * a default value for the attribute, then a XML::AttrDecl is * returned. * * namespace: The URI of the attribute's namespace. * name: The name of the attribute, not including a namespace. * * doc.root.attributes.get_attribute_ns('http://www.w3.org/1999/xlink', 'href') */ static VALUE rxml_attributes_get_attribute_ns(VALUE self, VALUE namespace, VALUE name) { xmlNodePtr xnode; xmlAttrPtr xattr; name = rb_obj_as_string(name); Data_Get_Struct(self, xmlNode, xnode); xattr = xmlHasNsProp(xnode, (xmlChar*) StringValuePtr(name), (xmlChar*) StringValuePtr(namespace)); if (!xattr) return Qnil; else if (xattr->type == XML_ATTRIBUTE_DECL) return rxml_attr_decl_wrap((xmlAttributePtr)xattr); else return rxml_attr_wrap(xattr); } /* * call-seq: * attributes["name"] -> String * * Fetches an attribute value. If you want to access the underlying * Attribute itself use get_attribute. * * name: The name of the attribute, not including any namespaces. * * doc.root.attributes['att'] -> 'some value' */ VALUE rxml_attributes_attribute_get(VALUE self, VALUE name) { VALUE xattr = rxml_attributes_get_attribute(self, name); if (NIL_P(xattr)) return Qnil; else return rxml_attr_value_get(xattr); } /* * call-seq: * attributes["name"] = "value" * * Sets an attribute value. If you want to get the Attribute itself, * use get_attribute. * * name: The name of the attribute, not including any namespaces. * value: The new value of the namespace. * * doc.root.attributes['att'] = 'some value' */ VALUE rxml_attributes_attribute_set(VALUE self, VALUE name, VALUE value) { VALUE xattr = rxml_attributes_get_attribute(self, name); if (NIL_P(xattr)) { VALUE args[3]; args[0] = rxml_attributes_node_get(self); args[1] = name; args[2] = value; return rb_class_new_instance(sizeof(args)/sizeof(VALUE), args, cXMLAttr); } else { return rxml_attr_value_set(xattr, value); } } /* * call-seq: * attributes.each {block} -> XML::Attr * * Iterates over each attribute. * * doc.root.attributes.each {|attribute| puts attribute.name} */ static VALUE rxml_attributes_each(VALUE self) { xmlNodePtr xnode; xmlAttrPtr xattr; Data_Get_Struct(self, xmlNode, xnode); xattr = xnode->properties; while (xattr) { /* Get the next attribute while we still can - the user may remove the yielded attribute. */ xmlAttrPtr next = xattr->next; VALUE attr = rxml_attr_wrap(xattr); rb_yield(attr); xattr = next; } return self; } /* * call-seq: * attributes.length -> Integer * * Returns the number of attributes. * * doc.root.attributes.length */ static VALUE rxml_attributes_length(VALUE self) { int length = 0; xmlNodePtr xnode; xmlAttrPtr xattr; Data_Get_Struct(self, xmlNode, xnode); xattr = xnode->properties; while (xattr) { length++; xattr = xattr->next; } return INT2NUM(length); } /* * call-seq: * attributes.first -> XML::Attr * * Returns the first attribute. * * doc.root.attributes.first */ static VALUE rxml_attributes_first(VALUE self) { xmlNodePtr xnode; Data_Get_Struct(self, xmlNode, xnode); if (xnode->type == XML_ELEMENT_NODE) { xmlAttrPtr xattr = xnode->properties; if (xattr) { return rxml_attr_wrap(xattr); } } return Qnil; } void rxml_init_attributes(void) { cXMLAttributes = rb_define_class_under(mXML, "Attributes", rb_cObject); rb_undef_alloc_func(cXMLAttributes); rb_include_module(cXMLAttributes, rb_mEnumerable); rb_define_method(cXMLAttributes, "node", rxml_attributes_node_get, 0); rb_define_method(cXMLAttributes, "get_attribute", rxml_attributes_get_attribute, 1); rb_define_method(cXMLAttributes, "get_attribute_ns", rxml_attributes_get_attribute_ns, 2); rb_define_method(cXMLAttributes, "[]", rxml_attributes_attribute_get, 1); rb_define_method(cXMLAttributes, "[]=", rxml_attributes_attribute_set, 2); rb_define_method(cXMLAttributes, "each", rxml_attributes_each, 0); rb_define_method(cXMLAttributes, "length", rxml_attributes_length, 0); rb_define_method(cXMLAttributes, "first", rxml_attributes_first, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_xinclude.h0000644000004100000410000000036114620142101022000 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_XINCLUDE__ #define __RXML_XINCLUDE__ extern VALUE cXMLXInclude; extern VALUE eXMLXIncludeError; void rxml_init_xinclude(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_encoding.c0000644000004100000410000002023714620142101021752 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include #include "ruby_libxml.h" /* * Document-class: LibXML::XML::Encoding * * The encoding class exposes the encodings that libxml * supports via constants. * * LibXML converts all data sources to UTF8 * internally before processing them. By default, * LibXML determines a data source's encoding * using the algorithm described on its * website[http://xmlsoft.org/encoding.html]. * * However, you may override a data source's encoding * by using the encoding constants defined in this * module. * * Example 1: * * io = File.open('some_file', 'rb') * parser = XML::Parser.io(io, :encoding => XML::Encoding::ISO_8859_1) * doc = parser.parse * * Example 2: * * parser = XML::HTMLParser.file("some_file", :encoding => XML::Encoding::ISO_8859_1) * doc = parser.parse * * Example 3: * * document = XML::Document.new * document.encoding = XML::Encoding::ISO_8859_1 * doc << XML::Node.new */ VALUE mXMLEncoding; /* * call-seq: * Encoding.from_s("UTF_8") -> XML::Encoding::UTF_8 * * Converts an encoding string to an encoding constant * defined on the XML::Encoding class. */ static VALUE rxml_encoding_from_s(VALUE klass, VALUE encoding) { xmlCharEncoding xencoding; if (encoding == Qnil) return Qnil; xencoding = xmlParseCharEncoding(StringValuePtr(encoding)); return INT2NUM(xencoding); } /* * call-seq: * Encoding.to_s(XML::Encoding::UTF_8) -> "UTF-8" * * Converts an encoding constant defined on the XML::Encoding * class to its text representation. */ static VALUE rxml_encoding_to_s(VALUE klass, VALUE encoding) { const xmlChar* xencoding = (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding)); if (!xencoding) return Qnil; else return rxml_new_cstr(xencoding, xencoding); } /* * Converts an xmlCharEncoding enum value into a Ruby Encoding object (available * on Ruby 1.9.* and higher). */ rb_encoding* rxml_xml_encoding_to_rb_encoding(VALUE klass, xmlCharEncoding xmlEncoding) { const char* encodingName; switch (xmlEncoding) { case XML_CHAR_ENCODING_UTF8: encodingName = "UTF-8"; break; case XML_CHAR_ENCODING_UTF16LE: encodingName = "UTF-16LE"; break; case XML_CHAR_ENCODING_UTF16BE: encodingName = "UTF-16BE"; break; case XML_CHAR_ENCODING_UCS4LE: encodingName = "UCS-4LE"; break; case XML_CHAR_ENCODING_UCS4BE: encodingName = "UCS-4BE"; break; case XML_CHAR_ENCODING_UCS2: encodingName = "UCS-2"; break; case XML_CHAR_ENCODING_8859_1: encodingName = "ISO8859-1"; break; case XML_CHAR_ENCODING_8859_2: encodingName = "ISO8859-2"; break; case XML_CHAR_ENCODING_8859_3: encodingName = "ISO8859-3"; break; case XML_CHAR_ENCODING_8859_4: encodingName = "ISO8859-4"; break; case XML_CHAR_ENCODING_8859_5: encodingName = "ISO8859-5"; break; case XML_CHAR_ENCODING_8859_6: encodingName = "ISO8859-6"; break; case XML_CHAR_ENCODING_8859_7: encodingName = "ISO8859-7"; break; case XML_CHAR_ENCODING_8859_8: encodingName = "ISO8859-8"; break; case XML_CHAR_ENCODING_8859_9: encodingName = "ISO8859-9"; break; case XML_CHAR_ENCODING_2022_JP: encodingName = "ISO-2022-JP"; break; case XML_CHAR_ENCODING_SHIFT_JIS: encodingName = "SHIFT-JIS"; break; case XML_CHAR_ENCODING_EUC_JP: encodingName = "EUC-JP"; break; case XML_CHAR_ENCODING_ASCII: encodingName = "US-ASCII"; break; default: /* Covers XML_CHAR_ENCODING_ERROR, XML_CHAR_ENCODING_NONE, XML_CHAR_ENCODING_EBCDIC */ encodingName = "ASCII-8BIT"; break; } return rb_enc_find(encodingName); } /* * call-seq: * Input.encoding_to_rb_encoding(Input::ENCODING) -> Encoding * * Converts an encoding constant defined on the XML::Encoding * class to a Ruby encoding object (available on Ruby 1.9.* and higher). */ VALUE rxml_encoding_to_rb_encoding(VALUE klass, VALUE encoding) { xmlCharEncoding xmlEncoding = (xmlCharEncoding)NUM2INT(encoding); rb_encoding* rbencoding = rxml_xml_encoding_to_rb_encoding(klass, xmlEncoding); return rb_enc_from_encoding(rbencoding); } rb_encoding* rxml_figure_encoding(const xmlChar* xencoding) { rb_encoding* result; if (xencoding) { xmlCharEncoding xmlEncoding = xmlParseCharEncoding((const char*)xencoding); result = rxml_xml_encoding_to_rb_encoding(mXMLEncoding, xmlEncoding); } else { result = rb_utf8_encoding(); } return result; } VALUE rxml_new_cstr(const xmlChar* xstr, const xmlChar* xencoding) { rb_encoding *rbencoding = rxml_figure_encoding(xencoding); return rb_external_str_new_with_enc((const char*)xstr, (long)strlen((const char*)xstr), rbencoding); } VALUE rxml_new_cstr_len(const xmlChar* xstr, const long length, const xmlChar* xencoding) { rb_encoding *rbencoding = rxml_figure_encoding(xencoding); return rb_external_str_new_with_enc((const char*)xstr, length, rbencoding); } void rxml_init_encoding(void) { mXMLEncoding = rb_define_module_under(mXML, "Encoding"); rb_define_module_function(mXMLEncoding, "from_s", rxml_encoding_from_s, 1); rb_define_module_function(mXMLEncoding, "to_s", rxml_encoding_to_s, 1); rb_define_module_function(mXMLEncoding, "to_rb_encoding", rxml_encoding_to_rb_encoding, 1); /* -1: No char encoding detected. */ rb_define_const(mXMLEncoding, "ERROR", INT2NUM(XML_CHAR_ENCODING_ERROR)); /* 0: No char encoding detected. */ rb_define_const(mXMLEncoding, "NONE", INT2NUM(XML_CHAR_ENCODING_NONE)); /* 1: UTF-8 */ rb_define_const(mXMLEncoding, "UTF_8", INT2NUM(XML_CHAR_ENCODING_UTF8)); /* 2: UTF-16 little endian. */ rb_define_const(mXMLEncoding, "UTF_16LE", INT2NUM(XML_CHAR_ENCODING_UTF16LE)); /* 3: UTF-16 big endian. */ rb_define_const(mXMLEncoding, "UTF_16BE", INT2NUM(XML_CHAR_ENCODING_UTF16BE)); /* 4: UCS-4 little endian. */ rb_define_const(mXMLEncoding, "UCS_4LE", INT2NUM(XML_CHAR_ENCODING_UCS4LE)); /* 5: UCS-4 big endian. */ rb_define_const(mXMLEncoding, "UCS_4BE", INT2NUM(XML_CHAR_ENCODING_UCS4BE)); /* 6: EBCDIC uh! */ rb_define_const(mXMLEncoding, "EBCDIC", INT2NUM(XML_CHAR_ENCODING_EBCDIC)); /* 7: UCS-4 unusual ordering. */ rb_define_const(mXMLEncoding, "UCS_4_2143", INT2NUM(XML_CHAR_ENCODING_UCS4_2143)); /* 8: UCS-4 unusual ordering. */ rb_define_const(mXMLEncoding, "UCS_4_3412", INT2NUM(XML_CHAR_ENCODING_UCS4_3412)); /* 9: UCS-2. */ rb_define_const(mXMLEncoding, "UCS_2", INT2NUM(XML_CHAR_ENCODING_UCS2)); /* 10: ISO-8859-1 ISO Latin 1. */ rb_define_const(mXMLEncoding, "ISO_8859_1", INT2NUM(XML_CHAR_ENCODING_8859_1)); /* 11: ISO-8859-2 ISO Latin 2. */ rb_define_const(mXMLEncoding, "ISO_8859_2", INT2NUM(XML_CHAR_ENCODING_8859_2)); /* 12: ISO-8859-3. */ rb_define_const(mXMLEncoding, "ISO_8859_3", INT2NUM(XML_CHAR_ENCODING_8859_3)); /* 13: ISO-8859-4. */ rb_define_const(mXMLEncoding, "ISO_8859_4", INT2NUM(XML_CHAR_ENCODING_8859_4)); /* 14: ISO-8859-5. */ rb_define_const(mXMLEncoding, "ISO_8859_5", INT2NUM(XML_CHAR_ENCODING_8859_5)); /* 15: ISO-8859-6. */ rb_define_const(mXMLEncoding, "ISO_8859_6", INT2NUM(XML_CHAR_ENCODING_8859_6)); /* 16: ISO-8859-7. */ rb_define_const(mXMLEncoding, "ISO_8859_7", INT2NUM(XML_CHAR_ENCODING_8859_7)); /* 17: ISO-8859-8. */ rb_define_const(mXMLEncoding, "ISO_8859_8", INT2NUM(XML_CHAR_ENCODING_8859_8)); /* 18: ISO-8859-9. */ rb_define_const(mXMLEncoding, "ISO_8859_9", INT2NUM(XML_CHAR_ENCODING_8859_9)); /* 19: ISO-2022-JP. */ rb_define_const(mXMLEncoding, "ISO_2022_JP", INT2NUM(XML_CHAR_ENCODING_2022_JP)); /* 20: Shift_JIS. */ rb_define_const(mXMLEncoding, "SHIFT_JIS", INT2NUM(XML_CHAR_ENCODING_SHIFT_JIS)); /* 21: EUC-JP. */ rb_define_const(mXMLEncoding, "EUC_JP", INT2NUM(XML_CHAR_ENCODING_EUC_JP)); /* 22: pure ASCII. */ rb_define_const(mXMLEncoding, "ASCII", INT2NUM(XML_CHAR_ENCODING_ASCII)); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_parser.c0000644000004100000410000000476214620142101021465 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include #include "ruby_libxml.h" /* * Document-class: LibXML::XML::Parser * * The XML::Parser provides a tree based API for processing * xml documents, in contract to XML::Reader's stream * based api and XML::SaxParser callback based API. * * As a result, parsing a document creates an in-memory document object * that consist of any number of XML::Node instances. This is simple * and powerful model, but has the major limitation that the size of * the document that can be processed is limited by the amount of * memory available. In such cases, it is better to use the XML::Reader. * * Using the parser is simple: * * parser = XML::Parser.file('my_file') * doc = parser.parse * * You can also parse documents (see XML::Parser.document), * strings (see XML::Parser.string) and io objects (see * XML::Parser.io). */ VALUE cXMLParser; static ID CONTEXT_ATTR; /* * call-seq: * parser.initialize(context) -> XML::Parser * * Creates a new XML::Parser from the specified * XML::Parser::Context. */ static VALUE rxml_parser_initialize(int argc, VALUE *argv, VALUE self) { VALUE context = Qnil; rb_scan_args(argc, argv, "01", &context); if (context == Qnil) { rb_raise(rb_eArgError, "An instance of a XML::Parser::Context must be passed to XML::Parser.new"); } rb_ivar_set(self, CONTEXT_ATTR, context); return self; } /* * call-seq: * parser.parse -> XML::Document * * Parse the input XML and create an XML::Document with * it's content. If an error occurs, XML::Parser::ParseError * is thrown. */ static VALUE rxml_parser_parse(VALUE self) { xmlParserCtxtPtr ctxt; VALUE context = rb_ivar_get(self, CONTEXT_ATTR); Data_Get_Struct(context, xmlParserCtxt, ctxt); if ((xmlParseDocument(ctxt) == -1 || !ctxt->wellFormed) && ! ctxt->recovery) { rxml_raise(&ctxt->lastError); } rb_funcall(context, rb_intern("close"), 0); return rxml_document_wrap(ctxt->myDoc); } void rxml_init_parser(void) { cXMLParser = rb_define_class_under(mXML, "Parser", rb_cObject); /* Atributes */ CONTEXT_ATTR = rb_intern("@context"); rb_define_attr(cXMLParser, "input", 1, 0); rb_define_attr(cXMLParser, "context", 1, 0); /* Instance Methods */ rb_define_method(cXMLParser, "initialize", rxml_parser_initialize, -1); rb_define_method(cXMLParser, "parse", rxml_parser_parse, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema_facet.h0000644000004100000410000000030714620142101022567 0ustar www-datawww-data#ifndef __RXML_SCHEMA_FACET__ #define __RXML_SCHEMA_FACET__ extern VALUE cXMLSchemaFacet; VALUE rxml_wrap_schema_facet(xmlSchemaFacetPtr facet); void rxml_init_schema_facet(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_cbg.c0000644000004100000410000000416514620142101020721 0ustar www-datawww-data#include "ruby_libxml.h" #include #include /* int xmlRegisterInputCallbacks (xmlInputMatchCallback matchFunc, xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, xmlInputCloseCallback closeFunc); int (*xmlInputMatchCallback) (char const *filename); void* (*xmlInputOpenCallback) (char const *filename); int (*xmlInputReadCallback) (void *context, char *buffer, int len); int (*xmlInputCloseCallback) (void *context); */ typedef struct deb_doc_context { char *buffer; char *bpos; int remaining; } deb_doc_context; int deb_Match(char const *filename) { fprintf(stderr, "deb_Match: %s\n", filename); if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "deb://", 6)) { return (1); } return (0); } void* deb_Open(char const *filename) { deb_doc_context *deb_doc; VALUE res; deb_doc = (deb_doc_context*) malloc(sizeof(deb_doc_context)); res = rb_funcall(rb_funcall(rb_mKernel, rb_intern("const_get"), 1, rb_str_new2("DEBSystem")), rb_intern("document_query"), 1, rb_str_new2(filename)); deb_doc->buffer = strdup(StringValuePtr(res)); //deb_doc->buffer = strdup("serepes"); deb_doc->bpos = deb_doc->buffer; deb_doc->remaining = (int)strlen(deb_doc->buffer); return deb_doc; } int deb_Read(void *context, char *buffer, int len) { deb_doc_context *deb_doc; int ret_len; deb_doc = (deb_doc_context*) context; if (len >= deb_doc->remaining) { ret_len = deb_doc->remaining; } else { ret_len = len; } deb_doc->remaining -= ret_len; strncpy(buffer, deb_doc->bpos, ret_len); deb_doc->bpos += ret_len; return ret_len; } int deb_Close(void *context) { free(((deb_doc_context*) context)->buffer); free(context); return 1; } void deb_register_cbg(void) { xmlRegisterInputCallbacks(deb_Match, deb_Open, deb_Read, deb_Close); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_xpath_expression.h0000644000004100000410000000035714620142101023575 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_XPATH_EXPRESSION__ #define __RXML_XPATH_EXPRESSION__ extern VALUE cXMLXPathExpression; void rxml_init_xpath_expression(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_attr_decl.h0000644000004100000410000000046614620142101022134 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_ATTR_DECL__ #define __RXML_ATTR_DECL__ extern VALUE cXMLAttrDecl; void rxml_init_attr_decl(void); VALUE rxml_attr_decl_wrap(xmlAttributePtr xattribute); VALUE rxml_attr_decl_value_get(VALUE self); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_attr_decl.c0000644000004100000410000000705414620142101022127 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ /* * Document-class: LibXML::XML::AttrDecl * * At attribute declaration is used in XML::Dtds to define * what attributes are allowed on an element. An attribute * declaration defines an attribues name, data type and default * value (if any). */ #include "ruby_libxml.h" VALUE cXMLAttrDecl; void rxml_attr_decl_mark(xmlAttributePtr xattr) { rxml_node_mark((xmlNodePtr) xattr); } VALUE rxml_attr_decl_wrap(xmlAttributePtr xattr) { return Data_Wrap_Struct(cXMLAttrDecl, rxml_attr_decl_mark, NULL, xattr); } /* * call-seq: * attr_decl.doc -> XML::Document * * Returns this attribute declaration's document. */ static VALUE rxml_attr_decl_doc_get(VALUE self) { xmlAttributePtr xattr; Data_Get_Struct(self, xmlAttribute, xattr); if (xattr->doc == NULL) return Qnil; else return rxml_document_wrap(xattr->doc); } /* * call-seq: * attr_decl.name -> "name" * * Obtain this attribute declaration's name. */ static VALUE rxml_attr_decl_name_get(VALUE self) { xmlAttributePtr xattr; Data_Get_Struct(self, xmlAttribute, xattr); if (xattr->name == NULL) return Qnil; else return rxml_new_cstr( xattr->name, xattr->doc->encoding); } /* * call-seq: * attr_decl.next -> XML::AttrDecl * * Obtain the next attribute declaration. */ static VALUE rxml_attr_decl_next_get(VALUE self) { xmlAttributePtr xattr; Data_Get_Struct(self, xmlAttribute, xattr); if (xattr->next == NULL) return Qnil; else return rxml_attr_decl_wrap((xmlAttributePtr)xattr->next); } /* * call-seq: * attr_decl.type -> num * * Obtain this attribute declaration's type node type. */ static VALUE rxml_attr_decl_node_type(VALUE self) { xmlAttrPtr xattr; Data_Get_Struct(self, xmlAttr, xattr); return INT2NUM(xattr->type); } /* * call-seq: * attr_decl.parent -> XML::Dtd * * Obtain this attribute declaration's parent which * is an instance of a XML::DTD. */ static VALUE rxml_attr_decl_parent_get(VALUE self) { xmlAttributePtr xattr; Data_Get_Struct(self, xmlAttribute, xattr); if (xattr->parent == NULL) return Qnil; else return rxml_dtd_wrap(xattr->parent); } /* * call-seq: * attr_decl.prev -> (XML::AttrDecl | XML::ElementDecl) * * Obtain the previous attribute declaration or the owning * element declration (not implemented). */ static VALUE rxml_attr_decl_prev_get(VALUE self) { xmlAttributePtr xattr; Data_Get_Struct(self, xmlAttribute, xattr); if (xattr->prev == NULL) return Qnil; else return rxml_attr_decl_wrap((xmlAttributePtr)xattr->prev); } /* * call-seq: * attr_decl.value -> "value" * * Obtain the default value of this attribute declaration. */ VALUE rxml_attr_decl_value_get(VALUE self) { xmlAttributePtr xattr; Data_Get_Struct(self, xmlAttribute, xattr); if (xattr->defaultValue) return rxml_new_cstr(xattr->defaultValue, NULL); else return Qnil; } void rxml_init_attr_decl(void) { cXMLAttrDecl = rb_define_class_under(mXML, "AttrDecl", rb_cObject); rb_undef_alloc_func(cXMLAttrDecl); rb_define_method(cXMLAttrDecl, "doc", rxml_attr_decl_doc_get, 0); rb_define_method(cXMLAttrDecl, "name", rxml_attr_decl_name_get, 0); rb_define_method(cXMLAttrDecl, "next", rxml_attr_decl_next_get, 0); rb_define_method(cXMLAttrDecl, "node_type", rxml_attr_decl_node_type, 0); rb_define_method(cXMLAttrDecl, "parent", rxml_attr_decl_parent_get, 0); rb_define_method(cXMLAttrDecl, "prev", rxml_attr_decl_prev_get, 0); rb_define_method(cXMLAttrDecl, "value", rxml_attr_decl_value_get, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_namespace.h0000644000004100000410000000037414620142101022125 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_NAMESPACE__ #define __RXML_NAMESPACE__ extern VALUE cXMLNamespace; void rxml_init_namespace(void); VALUE rxml_namespace_wrap(xmlNsPtr xns); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_xpath_context.c0000644000004100000410000002427414620142101023061 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_xpath_context.h" #include "ruby_xml_xpath_expression.h" #if RUBY_ST_H #include #else #include #endif #include /* * Document-class: LibXML::XML::XPath::Context * * The XML::XPath::Context class is used to evaluate XPath * expressions. Generally, you should not directly use this class, * but instead use the XML::Document#find and XML::Node#find methods. * * doc = XML::Document.string('
content
') * context = XPath::Context.new(doc) * context.node = doc.root * context.register_namespaces_from_node(doc.root) * nodes = context.find('/header') */ VALUE cXMLXPathContext; static void rxml_xpath_context_free(xmlXPathContextPtr ctxt) { xmlXPathFreeContext(ctxt); } static void rxml_xpath_context_mark(xmlXPathContextPtr ctxt) { VALUE value = (VALUE)ctxt->doc->_private; rb_gc_mark(value); } static VALUE rxml_xpath_context_alloc(VALUE klass) { return Data_Wrap_Struct(cXMLXPathContext, rxml_xpath_context_mark, rxml_xpath_context_free, NULL); } /* call-seq: * XPath::Context.new(doc) -> XPath::Context * * Creates a new XPath context for the specified document. The * context can then be used to evaluate an XPath expression. * * doc = XML::Document.string('
hi
') * context = XPath::Context.new(doc) * nodes = XPath::Object.new('//first', context) * nodes.length == 1 */ static VALUE rxml_xpath_context_initialize(VALUE self, VALUE document) { xmlDocPtr xdoc; if (rb_obj_is_kind_of(document, cXMLDocument) != Qtrue) { rb_raise(rb_eTypeError, "Supplied argument must be a document or node."); } Data_Get_Struct(document, xmlDoc, xdoc); DATA_PTR(self) = xmlXPathNewContext(xdoc); return self; } /* * call-seq: * context.doc -> document * * Obtain the XML::Document this node belongs to. */ static VALUE rxml_xpath_context_doc(VALUE self) { xmlDocPtr xdoc = NULL; xmlXPathContextPtr ctxt; Data_Get_Struct(self, xmlXPathContext, ctxt); xdoc = ctxt->doc; return rxml_document_wrap(xdoc); } /* * call-seq: * context.register_namespace(prefix, uri) -> (true|false) * * Register the specified namespace URI with the specified prefix * in this context. * context.register_namespace('xi', 'http://www.w3.org/2001/XInclude') */ static VALUE rxml_xpath_context_register_namespace(VALUE self, VALUE prefix, VALUE uri) { xmlXPathContextPtr ctxt; Data_Get_Struct(self, xmlXPathContext, ctxt); /* Prefix could be a symbol. */ prefix = rb_obj_as_string(prefix); if (xmlXPathRegisterNs(ctxt, (xmlChar*) StringValuePtr(prefix), (xmlChar*) StringValuePtr(uri)) == 0) { return (Qtrue); } else { /* Should raise an exception, IMHO (whose?, why shouldnt it? -danj)*/ rb_warning("register namespace failed"); return (Qfalse); } } /* call-seq: * context.register_namespaces_from_node(node) -> self * * Helper method to read in namespaces defined on a node. * * doc = XML::Document.string('
hi
') * context = XPath::Context.new(doc) * context.register_namespaces_from_node(doc.root) */ static VALUE rxml_xpath_context_register_namespaces_from_node(VALUE self, VALUE node) { xmlXPathContextPtr xctxt; xmlNodePtr xnode; xmlNsPtr *xnsArr; Data_Get_Struct(self, xmlXPathContext, xctxt); if (rb_obj_is_kind_of(node, cXMLDocument) == Qtrue) { xmlDocPtr xdoc; Data_Get_Struct(node, xmlDoc, xdoc); xnode = xmlDocGetRootElement(xdoc); } else if (rb_obj_is_kind_of(node, cXMLNode) == Qtrue) { Data_Get_Struct(node, xmlNode, xnode); } else { rb_raise(rb_eTypeError, "The first argument must be a document or node."); } xnsArr = xmlGetNsList(xnode->doc, xnode); if (xnsArr) { xmlNsPtr xns = *xnsArr; while (xns) { /* If there is no prefix, then this is the default namespace. Skip it for now. */ if (xns->prefix) { VALUE prefix = rxml_new_cstr(xns->prefix, xctxt->doc->encoding); VALUE uri = rxml_new_cstr(xns->href, xctxt->doc->encoding); rxml_xpath_context_register_namespace(self, prefix, uri); } xns = xns->next; } xmlFree(xnsArr); } return self; } static int iterate_ns_hash(VALUE prefix, VALUE uri, VALUE self) { rxml_xpath_context_register_namespace(self, prefix, uri); return ST_CONTINUE; } /* * call-seq: * context.register_namespaces(["prefix:uri"]) -> self * * Register the specified namespaces in this context. There are * three different forms that libxml accepts. These include * a string, an array of strings, or a hash table: * * context.register_namespaces('xi:http://www.w3.org/2001/XInclude') * context.register_namespaces(['xlink:http://www.w3.org/1999/xlink', * 'xi:http://www.w3.org/2001/XInclude') * context.register_namespaces('xlink' => 'http://www.w3.org/1999/xlink', * 'xi' => 'http://www.w3.org/2001/XInclude') */ static VALUE rxml_xpath_context_register_namespaces(VALUE self, VALUE nslist) { char *cp; long i; VALUE rprefix, ruri; xmlXPathContextPtr xctxt; Data_Get_Struct(self, xmlXPathContext, xctxt); /* Need to loop through the 2nd argument and iterate through the * list of namespaces that we want to allow */ switch (TYPE(nslist)) { case T_STRING: cp = strchr(StringValuePtr(nslist), (int) ':'); if (cp == NULL) { rprefix = nslist; ruri = Qnil; } else { rprefix = rb_str_new(StringValuePtr(nslist), (long) ((intptr_t) cp - (intptr_t)StringValuePtr(nslist))); ruri = rxml_new_cstr((const xmlChar*)&cp[1], xctxt->doc->encoding); } /* Should test the results of this */ rxml_xpath_context_register_namespace(self, rprefix, ruri); break; case T_ARRAY: for (i = 0; i < RARRAY_LEN(nslist); i++) { rxml_xpath_context_register_namespaces(self, RARRAY_PTR(nslist)[i]); } break; case T_HASH: rb_hash_foreach(nslist, iterate_ns_hash, self); break; default: rb_raise( rb_eArgError, "Invalid argument type, only accept string, array of strings, or an array of arrays"); } return self; } /* * call-seq: * context.node = node * * Set the current node used by the XPath engine * doc = XML::Document.string('
hi
') * context.node = doc.root.first */ static VALUE rxml_xpath_context_node_set(VALUE self, VALUE node) { xmlXPathContextPtr xctxt; xmlNodePtr xnode; Data_Get_Struct(self, xmlXPathContext, xctxt); Data_Get_Struct(node, xmlNode, xnode); xctxt->node = xnode; return node; } /* * call-seq: * context.find("xpath") -> true|false|number|string|XML::XPath::Object * * Executes the provided xpath function. The result depends on the execution * of the xpath statement. It may be true, false, a number, a string or * a node set. */ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr) { xmlXPathContextPtr xctxt; xmlXPathObjectPtr xobject; xmlXPathCompExprPtr xcompexpr; Data_Get_Struct(self, xmlXPathContext, xctxt); if (TYPE(xpath_expr) == T_STRING) { VALUE expression = rb_check_string_type(xpath_expr); xobject = xmlXPathEval((xmlChar*) StringValueCStr(expression), xctxt); } else if (rb_obj_is_kind_of(xpath_expr, cXMLXPathExpression)) { Data_Get_Struct(xpath_expr, xmlXPathCompExpr, xcompexpr); xobject = xmlXPathCompiledEval(xcompexpr, xctxt); } else { rb_raise(rb_eTypeError, "Argument should be an instance of a String or XPath::Expression"); } return rxml_xpath_to_value(xctxt, xobject); } #if LIBXML_VERSION >= 20626 /* * call-seq: * context.enable_cache(size = nil) * * Enables an XPath::Context's built-in cache. If the cache is * enabled then XPath objects will be cached internally for reuse. * The size parameter controls sets the maximum number of XPath objects * that will be cached per XPath object type (node-set, string, number, * boolean, and misc objects). Set size to nil to use the default * cache size of 100. */ static VALUE rxml_xpath_context_enable_cache(int argc, VALUE *argv, VALUE self) { xmlXPathContextPtr xctxt; VALUE size; int value = -1; Data_Get_Struct(self, xmlXPathContext, xctxt); if (rb_scan_args(argc, argv, "01", &size) == 1) { value = NUM2INT(size); } if (xmlXPathContextSetCache(xctxt, 1, value, 0) == -1) rxml_raise(xmlGetLastError()); return self; } /* * call-seq: * context.disable_cache * * Disables an XPath::Context's built-in cache. */ static VALUE rxml_xpath_context_disable_cache(VALUE self) { xmlXPathContextPtr xctxt; Data_Get_Struct(self, xmlXPathContext, xctxt); if (xmlXPathContextSetCache(xctxt, 0, 0, 0) == -1) rxml_raise(xmlGetLastError()); return self; } #endif void rxml_init_xpath_context(void) { cXMLXPathContext = rb_define_class_under(mXPath, "Context", rb_cObject); rb_define_alloc_func(cXMLXPathContext, rxml_xpath_context_alloc); rb_define_method(cXMLXPathContext, "doc", rxml_xpath_context_doc, 0); rb_define_method(cXMLXPathContext, "initialize", rxml_xpath_context_initialize, 1); rb_define_method(cXMLXPathContext, "register_namespaces", rxml_xpath_context_register_namespaces, 1); rb_define_method(cXMLXPathContext, "register_namespaces_from_node", rxml_xpath_context_register_namespaces_from_node, 1); rb_define_method(cXMLXPathContext, "register_namespace", rxml_xpath_context_register_namespace, 2); rb_define_method(cXMLXPathContext, "node=", rxml_xpath_context_node_set, 1); rb_define_method(cXMLXPathContext, "find", rxml_xpath_context_find, 1); #if LIBXML_VERSION >= 20626 rb_define_method(cXMLXPathContext, "enable_cache", rxml_xpath_context_enable_cache, -1); rb_define_method(cXMLXPathContext, "disable_cache", rxml_xpath_context_disable_cache, 0); #endif } libxml-ruby-5.0.3/ext/libxml/ruby_xml_xpath.c0000644000004100000410000001412114620142101021303 0ustar www-datawww-data/* * Document-class: LibXML::XML::XPath * * The XML::XPath module is used to query XML documents. It is * usually accessed via the XML::Document#find or * XML::Node#find methods. For example: * * document.find('/foo', namespaces) -> XML::XPath::Object * * The optional namespaces parameter can be a string, array or * hash table. * * document.find('/foo', 'xlink:http://www.w3.org/1999/xlink') * document.find('/foo', ['xlink:http://www.w3.org/1999/xlink', * 'xi:http://www.w3.org/2001/XInclude') * document.find('/foo', 'xlink' => 'http://www.w3.org/1999/xlink', * 'xi' => 'http://www.w3.org/2001/XInclude') * * * === Working With Default Namespaces * * Finding namespaced elements and attributes can be tricky. * Lets work through an example of a document with a default * namespace: * * * * Phil Bogle's Contacts * * * To find nodes you must define the atom namespace for * libxml. One way to do this is: * * node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom') * * Alternatively, you can register the default namespace like this: * * doc.root.namespaces.default_prefix = 'atom' * node = doc.find('atom:title') * * === More Complex Namespace Examples * * Lets work through some more complex examples using the * following xml document: * * * * * * * * * * * * # Since the soap namespace is defined on the root * # node we can directly use it. * doc.find('/soap:Envelope') * * # Since the ns1 namespace is not defined on the root node * # we have to first register it with the xpath engine. * doc.find('//ns1:IdAndName', * 'ns1:http://domain.somewhere.com') * * # Since the getManufacturerNamesResponse element uses a default * # namespace we first have to give it a prefix and register * # it with the xpath engine. * doc.find('//ns:getManufacturerNamesResponse', * 'ns:http://services.somewhere.com') * * # Here is an example showing a complex namespace aware * # xpath expression. * doc.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse/ns0:IDAndNameList/ns1:IdAndName', * ['ns0:http://services.somewhere.com', 'ns1:http://domain.somewhere.com']) */ #include "ruby_libxml.h" #include VALUE mXPath; VALUE rxml_xpath_to_value(xmlXPathContextPtr xctxt, xmlXPathObjectPtr xobject) { VALUE result; int type; if (xobject == NULL) { /* xmlLastError is different than xctxt->lastError. Use xmlLastError since it has the message set while xctxt->lastError does not. */ const xmlError *xerror = xmlGetLastError(); rxml_raise(xerror); } switch (type = xobject->type) { case XPATH_NODESET: result = rxml_xpath_object_wrap(xctxt->doc, xobject); break; case XPATH_BOOLEAN: result = (xobject->boolval != 0) ? Qtrue : Qfalse; xmlXPathFreeObject(xobject); break; case XPATH_NUMBER: result = rb_float_new(xobject->floatval); xmlXPathFreeObject(xobject); break; case XPATH_STRING: result = rxml_new_cstr(xobject->stringval, xctxt->doc->encoding); xmlXPathFreeObject(xobject); break; default: xmlXPathFreeObject(xobject); rb_raise(rb_eTypeError, "can't convert XPath object of type %d to Ruby value", type ); } return result; } xmlXPathObjectPtr rxml_xpath_from_value(VALUE value) { xmlXPathObjectPtr result = NULL; switch (TYPE(value)) { case T_TRUE: case T_FALSE: result = xmlXPathNewBoolean(RTEST(value)); break; case T_FIXNUM: case T_FLOAT: result = xmlXPathNewFloat(NUM2DBL(value)); break; case T_STRING: result = xmlXPathWrapString(xmlStrdup((const xmlChar *)StringValuePtr(value))); break; case T_NIL: result = xmlXPathNewNodeSet(NULL); break; case T_ARRAY: { long i, j; result = xmlXPathNewNodeSet(NULL); for (i = RARRAY_LEN(value); i > 0; i--) { xmlXPathObjectPtr obj = rxml_xpath_from_value(rb_ary_shift(value)); if ((obj->nodesetval != NULL) && (obj->nodesetval->nodeNr != 0)) { for (j = 0; j < obj->nodesetval->nodeNr; j++) { xmlXPathNodeSetAdd(result->nodesetval, obj->nodesetval->nodeTab[j]); } } } break; } default: rb_raise(rb_eTypeError, "can't convert object of type %s to XPath object", rb_obj_classname(value) ); } return result; } void rxml_init_xpath(void) { mXPath = rb_define_module_under(mXML, "XPath"); /* 0: Undefined value. */ rb_define_const(mXPath, "UNDEFINED", INT2NUM(XPATH_UNDEFINED)); /* 1: A nodeset, will be wrapped by XPath Object. */ rb_define_const(mXPath, "NODESET", INT2NUM(XPATH_NODESET)); /* 2: A boolean value. */ rb_define_const(mXPath, "BOOLEAN", INT2NUM(XPATH_BOOLEAN)); /* 3: A numeric value. */ rb_define_const(mXPath, "NUMBER", INT2NUM(XPATH_NUMBER)); /* 4: A string value. */ rb_define_const(mXPath, "STRING", INT2NUM(XPATH_STRING)); /* 5: An xpointer point */ rb_define_const(mXPath, "POINT", INT2NUM(XPATH_POINT)); /* 6: An xpointer range */ rb_define_const(mXPath, "RANGE", INT2NUM(XPATH_RANGE)); /* 7: An xpointer location set */ rb_define_const(mXPath, "LOCATIONSET", INT2NUM(XPATH_LOCATIONSET)); /* 8: XPath user type */ rb_define_const(mXPath, "USERS", INT2NUM(XPATH_USERS)); /* 9: An XSLT value tree, non modifiable */ rb_define_const(mXPath, "XSLT_TREE", INT2NUM(XPATH_XSLT_TREE)); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_html_parser_context.c0000644000004100000410000002557514620142101024262 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #include "ruby_libxml.h" #include "ruby_xml_html_parser_context.h" #include /* * Document-class: LibXML::XML::HTMLParser::Context * * The XML::HTMLParser::Context class provides in-depth control over how * a document is parsed. */ VALUE cXMLHtmlParserContext; static ID IO_ATTR; /* OS X 10.5 ships with libxml2 version 2.6.16 which does not expose the htmlNewParserCtxt (or htmlInitParserCtxt which it uses) method. htmlNewParserCtxt wasn't added to the libxml2 header files until 2.6.27. So the next two methods are simply copied from a newer version of libxml2 (2.7.2). */ #if LIBXML_VERSION < 20627 #define XML_CTXT_FINISH_DTD_0 0xabcd1234 static int htmlInitParserCtxt(htmlParserCtxtPtr ctxt) { htmlSAXHandler *sax; if (ctxt == NULL) return(-1); memset(ctxt, 0, sizeof(htmlParserCtxt)); ctxt->dict = xmlDictCreate(); if (ctxt->dict == NULL) { rb_raise(rb_eNoMemError, "htmlInitParserCtxt: out of memory\n"); return(-1); } sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler)); if (sax == NULL) { rb_raise(rb_eNoMemError, "htmlInitParserCtxt: out of memory\n"); return(-1); } else memset(sax, 0, sizeof(htmlSAXHandler)); ctxt->inputTab = (htmlParserInputPtr *) xmlMalloc(5 * sizeof(htmlParserInputPtr)); if (ctxt->inputTab == NULL) { rb_raise(rb_eNoMemError, "htmlInitParserCtxt: out of memory\n"); ctxt->inputNr = 0; ctxt->inputMax = 0; ctxt->input = NULL; return(-1); } ctxt->inputNr = 0; ctxt->inputMax = 5; ctxt->input = NULL; ctxt->version = NULL; ctxt->encoding = NULL; ctxt->standalone = -1; ctxt->instate = XML_PARSER_START; ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr)); if (ctxt->nodeTab == NULL) { rb_raise(rb_eNoMemError, "htmlInitParserCtxt: out of memory\n"); ctxt->nodeNr = 0; ctxt->nodeMax = 0; ctxt->node = NULL; ctxt->inputNr = 0; ctxt->inputMax = 0; ctxt->input = NULL; return(-1); } ctxt->nodeNr = 0; ctxt->nodeMax = 10; ctxt->node = NULL; ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *)); if (ctxt->nameTab == NULL) { rb_raise(rb_eNoMemError, "htmlInitParserCtxt: out of memory\n"); ctxt->nameNr = 0; ctxt->nameMax = 10; ctxt->name = NULL; ctxt->nodeNr = 0; ctxt->nodeMax = 0; ctxt->node = NULL; ctxt->inputNr = 0; ctxt->inputMax = 0; ctxt->input = NULL; return(-1); } ctxt->nameNr = 0; ctxt->nameMax = 10; ctxt->name = NULL; if (sax == NULL) ctxt->sax = (xmlSAXHandlerPtr) &htmlDefaultSAXHandler; else { ctxt->sax = sax; memcpy(sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1)); } ctxt->userData = ctxt; ctxt->myDoc = NULL; ctxt->wellFormed = 1; ctxt->replaceEntities = 0; ctxt->linenumbers = xmlLineNumbersDefaultValue; ctxt->html = 1; ctxt->vctxt.finishDtd = XML_CTXT_FINISH_DTD_0; ctxt->vctxt.userData = ctxt; ctxt->vctxt.error = xmlParserValidityError; ctxt->vctxt.warning = xmlParserValidityWarning; ctxt->record_info = 0; ctxt->validate = 0; ctxt->nbChars = 0; ctxt->checkIndex = 0; ctxt->catalogs = NULL; xmlInitNodeInfoSeq(&ctxt->node_seq); return(0); } static htmlParserCtxtPtr htmlNewParserCtxt(void) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt)); if (ctxt == NULL) { rb_raise(rb_eNoMemError, "NewParserCtxt: out of memory\n"); return(NULL); } memset(ctxt, 0, sizeof(xmlParserCtxt)); if (htmlInitParserCtxt(ctxt) < 0) { htmlFreeParserCtxt(ctxt); return(NULL); } return(ctxt); } #endif static void rxml_html_parser_context_free(htmlParserCtxtPtr ctxt) { htmlFreeParserCtxt(ctxt); } static VALUE rxml_html_parser_context_wrap(htmlParserCtxtPtr ctxt) { return Data_Wrap_Struct(cXMLHtmlParserContext, NULL, rxml_html_parser_context_free, ctxt); } /* call-seq: * XML::HTMLParser::Context.file(file) -> XML::HTMLParser::Context * * Creates a new parser context based on the specified file or uri. * * Parameters: * * file - A filename or uri * options - A or'ed together list of LibXML::XML::HTMLParser::Options values */ static VALUE rxml_html_parser_context_file(int argc, VALUE* argv, VALUE klass) { VALUE file, options; rb_scan_args(argc, argv, "11", &file, &options); htmlParserCtxtPtr ctxt = htmlCreateFileParserCtxt(StringValuePtr(file), NULL); if (!ctxt) rxml_raise(xmlGetLastError()); /* This is annoying, but xmlInitParserCtxt (called indirectly above) and xmlCtxtUseOptionsInternal (called below) initialize slightly different context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */ htmlCtxtUseOptions(ctxt, options == Qnil ? 0 : NUM2INT(options)); return rxml_html_parser_context_wrap(ctxt); } /* call-seq: * XML::HTMLParser::Context.io(io) -> XML::HTMLParser::Context * * Creates a new parser context based on the specified io object. * * Parameters: * * io - A ruby IO object * options - A or'ed together list of LibXML::XML::HTMLParser::Options values */ static VALUE rxml_html_parser_context_io(int argc, VALUE* argv, VALUE klass) { VALUE io, options; rb_scan_args(argc, argv, "11", &io, &options); VALUE result; htmlParserCtxtPtr ctxt; xmlParserInputBufferPtr input; xmlParserInputPtr stream; if (NIL_P(io)) rb_raise(rb_eTypeError, "Must pass in an IO object"); input = xmlParserInputBufferCreateIO((xmlInputReadCallback) rxml_read_callback, NULL, (void*)io, XML_CHAR_ENCODING_NONE); ctxt = htmlNewParserCtxt(); if (!ctxt) { xmlFreeParserInputBuffer(input); rxml_raise(xmlGetLastError()); } /* This is annoying, but xmlInitParserCtxt (called indirectly above) and xmlCtxtUseOptionsInternal (called below) initialize slightly different context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */ htmlCtxtUseOptions(ctxt, options == Qnil ? 0 : NUM2INT(options)); stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); if (!stream) { xmlFreeParserInputBuffer(input); xmlFreeParserCtxt(ctxt); rxml_raise(xmlGetLastError()); } inputPush(ctxt, stream); result = rxml_html_parser_context_wrap(ctxt); /* Attach io object to parser so it won't get freed.*/ rb_ivar_set(result, IO_ATTR, io); return result; } /* call-seq: * XML::HTMLParser::Context.string(string) -> XML::HTMLParser::Context * * Creates a new parser context based on the specified string. * * Parameters: * * string - A string that contains the data to parse * options - A or'ed together list of LibXML::XML::HTMLParser::Options values */ static VALUE rxml_html_parser_context_string(int argc, VALUE* argv, VALUE klass) { VALUE string, options; rb_scan_args(argc, argv, "11", &string, &options); Check_Type(string, T_STRING); if (RSTRING_LEN(string) == 0) rb_raise(rb_eArgError, "Must specify a string with one or more characters"); htmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt(StringValuePtr(string), (int)RSTRING_LEN(string)); if (!ctxt) rxml_raise(xmlGetLastError()); /* This is annoying, but xmlInitParserCtxt (called indirectly above) and xmlCtxtUseOptionsInternal (called below) initialize slightly different context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */ htmlCtxtUseOptions(ctxt, options == Qnil ? 0 : NUM2INT(options)); // Setup sax handler // TODO - there must be a better way? The sax handler is initialized for XML, but we want // to use HTML memset(ctxt->sax, 0, sizeof(xmlSAXHandler)); xmlSAX2InitHtmlDefaultSAXHandler(ctxt->sax); return rxml_html_parser_context_wrap(ctxt); } /* * call-seq: * context.close -> nil * * Closes the underlying input streams. This is useful when parsing a large amount of * files and you want to close the files without relying on Ruby's garbage collector * to run. */ static VALUE rxml_html_parser_context_close(VALUE self) { htmlParserCtxtPtr ctxt; xmlParserInputPtr xinput; Data_Get_Struct(self, htmlParserCtxt, ctxt); while ((xinput = inputPop(ctxt)) != NULL) { xmlFreeInputStream(xinput); } return Qnil; } /* * call-seq: * context.disable_cdata = (true|false) * * Control whether the CDATA nodes will be created in this context. */ static VALUE rxml_html_parser_context_disable_cdata_set(VALUE self, VALUE value) { htmlParserCtxtPtr ctxt; Data_Get_Struct(self, htmlParserCtxt, ctxt); if (ctxt->sax == NULL) rb_raise(rb_eRuntimeError, "Sax handler is not yet set"); /* LibXML controls this internally with the default SAX handler. */ if (value) ctxt->sax->cdataBlock = NULL; else ctxt->sax->cdataBlock = xmlSAX2CDataBlock; return value; } /* * call-seq: * context.options = XML::Parser::Options::NOENT | XML::Parser::Options::NOCDATA * * Provides control over the execution of a parser. Valid values * are the constants defined on XML::Parser::Options. Multiple * options can be combined by using Bitwise OR (|). */ static VALUE rxml_html_parser_context_options_set(VALUE self, VALUE options) { int xml_options = NUM2INT(options); htmlParserCtxtPtr ctxt; Check_Type(options, T_FIXNUM); Data_Get_Struct(self, htmlParserCtxt, ctxt); htmlCtxtUseOptions(ctxt, xml_options); #if LIBXML_VERSION >= 20707 /* Big hack here, but htmlCtxtUseOptions doens't support HTML_PARSE_NOIMPLIED. So do it ourselves. There must be a better way??? */ if (xml_options & HTML_PARSE_NOIMPLIED) { ctxt->options |= HTML_PARSE_NOIMPLIED; } #endif return self; } void rxml_init_html_parser_context(void) { IO_ATTR = ID2SYM(rb_intern("@io")); cXMLHtmlParserContext = rb_define_class_under(cXMLHtmlParser, "Context", cXMLParserContext); rb_define_singleton_method(cXMLHtmlParserContext, "file", rxml_html_parser_context_file, -1); rb_define_singleton_method(cXMLHtmlParserContext, "io", rxml_html_parser_context_io, -1); rb_define_singleton_method(cXMLHtmlParserContext, "string", rxml_html_parser_context_string, -1); rb_define_method(cXMLHtmlParserContext, "close", rxml_html_parser_context_close, 0); rb_define_method(cXMLHtmlParserContext, "disable_cdata=", rxml_html_parser_context_disable_cdata_set, 1); rb_define_method(cXMLHtmlParserContext, "options=", rxml_html_parser_context_options_set, 1); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_error.h0000644000004100000410000000047614620142101021325 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_ERROR__ #define __RXML_ERROR__ #include extern VALUE eXMLError; void rxml_init_error(void); VALUE rxml_error_wrap(const xmlError *xerror); void rxml_raise(const xmlError *xerror); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_writer.h0000644000004100000410000000016414620142101021502 0ustar www-datawww-data#ifndef __RXML_WRITER__ #define __RXML_WRITER__ extern VALUE cXMLWriter; void rxml_init_writer(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_xpath_context.h0000644000004100000410000000034114620142101023053 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_XPATH_CONTEXT__ #define __RXML_XPATH_CONTEXT__ extern VALUE cXMLXPathContext; void rxml_init_xpath_context(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_version.h0000644000004100000410000000062614620142101021656 0ustar www-datawww-data/* Don't nuke this block! It is used for automatically updating the * versions below. VERSION = string formatting, VERNUM = numbered * version for inline testing: increment both or none at all.*/ #define RUBY_LIBXML_VERSION "5.0.3" #define RUBY_LIBXML_VERNUM 503 #define RUBY_LIBXML_VER_MAJ 5 #define RUBY_LIBXML_VER_MIN 0 #define RUBY_LIBXML_VER_MIC 3 #define RUBY_LIBXML_VER_PATCH 0 libxml-ruby-5.0.3/ext/libxml/ruby_xml_input_cbg.h0000644000004100000410000000053214620142101022137 0ustar www-datawww-data#ifndef _INPUT_CBG_ #define _INPUT_CBG_ void rxml_init_input_callbacks(void); typedef struct ic_doc_context { char *buffer; char *bpos; int remaining; } ic_doc_context; typedef struct ic_scheme { char *scheme_name; VALUE class; int name_len; struct ic_scheme *next_scheme; } ic_scheme; #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema.h0000644000004100000410000000117014620142101021424 0ustar www-datawww-data#ifndef __RXML_SCHEMA__ #define __RXML_SCHEMA__ #include #include typedef struct _xmlSchemaItemList xmlSchemaItemList; typedef xmlSchemaItemList *xmlSchemaItemListPtr; struct _xmlSchemaItemList { void **items; /* used for dynamic addition of schemata */ int nbItems; /* used for dynamic addition of schemata */ int sizeItems; /* used for dynamic addition of schemata */ }; #define QNIL_OR_STRING(slot) \ (slot == NULL) ? Qnil : rb_str_new2((const char *)slot) extern VALUE cXMLSchema; void rxml_init_schema(void); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema_attribute.c0000644000004100000410000000636014620142101023510 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_schema_attribute.h" #include "ruby_xml_schema_type.h" /** * xmlSchemaBasicItem: * * The abstract base type for schema components. */ typedef struct _xmlSchemaBasicItem xmlSchemaBasicItem; typedef xmlSchemaBasicItem *xmlSchemaBasicItemPtr; struct _xmlSchemaBasicItem { xmlSchemaTypeType type; }; /** * xmlSchemaQNameRef: * * A component reference item (not a schema component) * (Extends xmlSchemaBasicItem) */ typedef struct _xmlSchemaQNameRef xmlSchemaQNameRef; typedef xmlSchemaQNameRef *xmlSchemaQNameRefPtr; struct _xmlSchemaQNameRef { xmlSchemaTypeType type; xmlSchemaBasicItemPtr item; /* The resolved referenced item. */ xmlSchemaTypeType itemType; const xmlChar *name; const xmlChar *targetNamespace; xmlNodePtr node; }; /** * xmlSchemaAttributeUseProhibPtr: * * A helper component to reflect attribute prohibitions. * (Extends xmlSchemaBasicItem) */ typedef struct _xmlSchemaAttributeUseProhib xmlSchemaAttributeUseProhib; typedef xmlSchemaAttributeUseProhib *xmlSchemaAttributeUseProhibPtr; struct _xmlSchemaAttributeUseProhib { xmlSchemaTypeType type; /* == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB */ xmlNodePtr node; const xmlChar *name; const xmlChar *targetNamespace; int isRef; }; VALUE cXMLSchemaAttribute; static void rxml_schema_attribute_free(xmlSchemaAttributeUsePtr attr) { attr = NULL; xmlFree(attr); } VALUE rxml_wrap_schema_attribute(xmlSchemaAttributeUsePtr attr) { VALUE result; const xmlChar *tns_str, *name_str; if (!attr) rb_raise(rb_eArgError, "XML::Schema::Attribute required!"); result = Data_Wrap_Struct(cXMLSchemaAttribute, NULL, rxml_schema_attribute_free, attr); if (attr->type == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB) { tns_str = ((xmlSchemaAttributeUseProhibPtr) attr)->targetNamespace; name_str = ((xmlSchemaAttributeUseProhibPtr) attr)->name; } else if (attr->type == XML_SCHEMA_EXTRA_QNAMEREF) { tns_str = ((xmlSchemaQNameRefPtr) attr)->targetNamespace; name_str = ((xmlSchemaQNameRefPtr) attr)->name; } else { tns_str = ((xmlSchemaAttributePtr) (attr->attrDecl))->targetNamespace; name_str = ((xmlSchemaAttributePtr) (attr->attrDecl))->name; } rb_iv_set(result, "@target_namespace", QNIL_OR_STRING(tns_str)); rb_iv_set(result, "@name", QNIL_OR_STRING(name_str)); rb_iv_set(result, "@type", rxml_wrap_schema_type((xmlSchemaTypePtr)attr->attrDecl->subtypes)); rb_iv_set(result, "@value", QNIL_OR_STRING(attr->defValue)); rb_iv_set(result, "@occurs", INT2NUM(attr->occurs)); return result; } static VALUE rxml_schema_attribute_node(VALUE self) { xmlSchemaAttributeUsePtr attr; Data_Get_Struct(self, xmlSchemaAttributeUse, attr); return rxml_node_wrap(attr->node); } void rxml_init_schema_attribute(void) { cXMLSchemaAttribute = rb_define_class_under(cXMLSchema, "Attribute", rb_cObject); rb_undef_alloc_func(cXMLSchemaAttribute); rb_define_attr(cXMLSchemaAttribute, "name", 1, 0); rb_define_attr(cXMLSchemaAttribute, "type", 1, 0); rb_define_attr(cXMLSchemaAttribute, "namespace", 1, 0); rb_define_attr(cXMLSchemaAttribute, "value", 1, 0); rb_define_attr(cXMLSchemaAttribute, "occurs", 1, 0); rb_define_method(cXMLSchemaAttribute, "node", rxml_schema_attribute_node, 0); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_attr.h0000644000004100000410000000050214620142101021134 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_ATTR__ #define __RXML_ATTR__ extern VALUE cXMLAttr; void rxml_init_attr(void); VALUE rxml_attr_wrap(xmlAttrPtr xattr); VALUE rxml_attr_value_get(VALUE self); VALUE rxml_attr_value_set(VALUE self, VALUE val); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_xpath.h0000644000004100000410000000052414620142101021312 0ustar www-datawww-data/* Please see the LICENSE file for copyright and distribution information */ #ifndef __RXML_XPATH__ #define __RXML_XPATH__ #include extern VALUE mXPath; void rxml_init_xpath(void); VALUE rxml_xpath_to_value(xmlXPathContextPtr, xmlXPathObjectPtr); xmlXPathObjectPtr rxml_xpath_from_value(VALUE); #endif libxml-ruby-5.0.3/ext/libxml/ruby_xml_schema_type.c0000644000004100000410000001451614620142101022470 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_schema_type.h" #include "ruby_xml_schema_element.h" #include "ruby_xml_schema_attribute.h" #include "ruby_xml_schema_facet.h" #define UNBOUNDED 1 << 30 #define FREE_AND_NULL(str) if ((str) != NULL) { xmlFree((xmlChar *) (str)); str = NULL; } /** * xmlSchemaTreeItem: * * The abstract base type for tree-like structured schema components. * (Extends xmlSchemaAnnotItem) */ typedef struct _xmlSchemaTreeItem xmlSchemaTreeItem; typedef xmlSchemaTreeItem *xmlSchemaTreeItemPtr; struct _xmlSchemaTreeItem { xmlSchemaTypeType type; xmlSchemaAnnotPtr annot; xmlSchemaTreeItemPtr next; xmlSchemaTreeItemPtr children; }; /** * xmlSchemaParticle: * * A particle component. * (Extends xmlSchemaTreeItem) */ typedef struct _xmlSchemaParticle xmlSchemaParticle; typedef xmlSchemaParticle *xmlSchemaParticlePtr; struct _xmlSchemaParticle { xmlSchemaTypeType type; xmlSchemaAnnotPtr annot; xmlSchemaTreeItemPtr next; /* next particle */ xmlSchemaTreeItemPtr children; /* the "term" (e.g. a model group, a group definition, a XML_SCHEMA_EXTRA_QNAMEREF (if a reference), etc.) */ int minOccurs; int maxOccurs; xmlNodePtr node; }; VALUE cXMLSchemaType; static void rxml_schema_type_free(xmlSchemaTypePtr xschema_type) { xschema_type = NULL; xmlFree(xschema_type); } VALUE rxml_wrap_schema_type(xmlSchemaTypePtr xtype) { VALUE result; if (!xtype) rb_raise(rb_eArgError, "XML::Schema::Type required!"); result = Data_Wrap_Struct(cXMLSchemaType, NULL, rxml_schema_type_free, xtype); rb_iv_set(result, "@name", QNIL_OR_STRING(xtype->name)); rb_iv_set(result, "@namespace", QNIL_OR_STRING(xtype->targetNamespace)); rb_iv_set(result, "@kind", INT2NUM(xtype->type)); return result; } static VALUE rxml_schema_type_base(VALUE self) { xmlSchemaTypePtr xtype; Data_Get_Struct(self, xmlSchemaType, xtype); return (xtype->baseType != xtype) ? rxml_wrap_schema_type(xtype->baseType) : Qnil; } static VALUE rxml_schema_type_node(VALUE self) { xmlSchemaTypePtr xtype; Data_Get_Struct(self, xmlSchemaType, xtype); return (xtype->node != NULL) ? rxml_node_wrap(xtype->node) : Qnil; } static VALUE rxml_schema_type_facets(VALUE self) { xmlSchemaTypePtr xtype; xmlSchemaFacetPtr xfacet; VALUE result = rb_ary_new(); VALUE facet; Data_Get_Struct(self, xmlSchemaType, xtype); xfacet = xtype->facets; while (xfacet != NULL) { facet = rxml_wrap_schema_facet((xmlSchemaFacetPtr)xfacet); rb_ary_push(result, facet); xfacet = xfacet->next; } return result; } static VALUE rxml_schema_type_annot(VALUE self) { VALUE result = Qnil; xmlSchemaTypePtr xtype; Data_Get_Struct(self, xmlSchemaType, xtype); if(xtype != NULL && xtype->annot != NULL && xtype->annot->content != NULL) { xmlChar *content = xmlNodeGetContent(xtype->annot->content); if (content) { result = rxml_new_cstr(content, NULL); xmlFree(content); } } return result; } static void rxmlSchemaCollectElements(xmlSchemaParticlePtr xparticle, VALUE hash) { VALUE element; xmlSchemaTreeItemPtr xterm; if (xparticle == NULL) return; xterm = xparticle->children; if (xterm != NULL) { switch (xterm->type) { case XML_SCHEMA_TYPE_ELEMENT: element = rxml_wrap_schema_element((xmlSchemaElementPtr)xterm); rb_iv_set(element, "@min", INT2NUM(xparticle->minOccurs)); if (xparticle->maxOccurs >= UNBOUNDED) rb_iv_set(element, "@max", rb_const_get(rb_path2class("Float"), rb_intern("INFINITY"))); else rb_iv_set(element, "@max", INT2NUM(xparticle->maxOccurs)); if (xparticle->annot != NULL) { xmlChar *content = xmlNodeGetContent(xparticle->annot->content); if (content != NULL) { rb_iv_set(element, "@annotation", rb_str_new2((const char *) content)); xmlFree(content); } } rb_hash_aset(hash, rb_str_new2((const char *) ((xmlSchemaElementPtr)xterm)->name), element); break; case XML_SCHEMA_TYPE_SEQUENCE: break; case XML_SCHEMA_TYPE_CHOICE: break; case XML_SCHEMA_TYPE_ALL: break; case XML_SCHEMA_TYPE_ANY: break; default: return; } } if (xterm && ((xterm->type == XML_SCHEMA_TYPE_SEQUENCE) || (xterm->type == XML_SCHEMA_TYPE_CHOICE) || (xterm->type == XML_SCHEMA_TYPE_ALL)) && (xterm->children != NULL)) { rxmlSchemaCollectElements((xmlSchemaParticlePtr)xterm->children, hash); } if (xparticle->next != NULL) { rxmlSchemaCollectElements((xmlSchemaParticlePtr)xparticle->next, hash); } } static VALUE rxml_schema_type_elements(VALUE self) { VALUE result = rb_hash_new(); xmlSchemaTypePtr xtype; Data_Get_Struct(self, xmlSchemaType, xtype); rxmlSchemaCollectElements((xmlSchemaParticlePtr) xtype->subtypes, result); return result; } static VALUE rxml_schema_type_attributes(VALUE self) { VALUE result = rb_ary_new(); xmlSchemaTypePtr xtype; xmlSchemaAttributeUsePtr xuse; xmlSchemaItemListPtr xuses; int i; Data_Get_Struct(self, xmlSchemaType, xtype); xuses = xtype->attrUses; if (xuses != NULL) { for (i = 0; i < xuses->nbItems; i++) { xuse = (xmlSchemaAttributeUsePtr)xuses->items[i]; rb_ary_push(result, rxml_wrap_schema_attribute(xuse)); } } return result; } void rxml_init_schema_type(void) { /* Add in infinity support for ruby 1.8.7 */ #if !defined(RUBY_VM) && defined(INFINITY) ID infinityId = rb_intern("INFINITY"); if (rb_const_defined(rb_cFloat, infinityId) == Qfalse) rb_define_const(rb_cFloat, "INFINITY", rb_float_new(INFINITY)); #endif cXMLSchemaType = rb_define_class_under(cXMLSchema, "Type", rb_cObject); rb_undef_alloc_func(cXMLSchemaType); rb_define_attr(cXMLSchemaType, "namespace", 1, 0); rb_define_attr(cXMLSchemaType, "name", 1, 0); rb_define_attr(cXMLSchemaType, "kind", 1, 0); rb_define_method(cXMLSchemaType, "base", rxml_schema_type_base, 0); rb_define_method(cXMLSchemaType, "node", rxml_schema_type_node, 0); rb_define_method(cXMLSchemaType, "elements", rxml_schema_type_elements, 0); rb_define_method(cXMLSchemaType, "attributes", rxml_schema_type_attributes, 0); rb_define_method(cXMLSchemaType, "facets", rxml_schema_type_facets, 0); rb_define_method(cXMLSchemaType, "annotation", rxml_schema_type_annot, 0); } libxml-ruby-5.0.3/ext/libxml/libxml.c0000644000004100000410000000365314620142101017535 0ustar www-datawww-data#include "ruby_libxml.h" #if RUBY_INTERN_H #include #else #include #endif VALUE mLibXML; static void rxml_init_memory(void) { /* Disable for now - broke attributes. xmlGcMemSetup( (xmlFreeFunc)ruby_xfree, (xmlMallocFunc)ruby_xmalloc, (xmlMallocFunc)ruby_xmalloc, (xmlReallocFunc)ruby_xrealloc, (xmlStrdupFunc)ruby_strdup );*/ } void Init_libxml_ruby(void) { /* The libxml gem provides Ruby language bindings for GNOME's Libxml2 * XML toolkit. To get started you may: * * require 'test_helper' * document = XML::Document.new * * However, when creating an application or library you plan to * redistribute, it is best to not add the LibXML module to the global * namespace, in which case you can either write your code like this: * * require 'libxml' * document = LibXML::XML::Document.new * * Refer to the README file to get started and the LICENSE file for * copyright and distribution information. */ // Seutp for threading. http://xmlsoft.org/threads.html xmlInitParser(); mLibXML = rb_define_module("LibXML"); rxml_init_memory(); rxml_init_xml(); rxml_init_io(); rxml_init_error(); rxml_init_encoding(); rxml_init_parser(); rxml_init_parser_context(); rxml_init_parser_options(); rxml_init_node(); rxml_init_attributes(); rxml_init_attr(); rxml_init_attr_decl(); rxml_init_document(); rxml_init_namespaces(); rxml_init_namespace(); rxml_init_sax_parser(); rxml_init_sax2_handler(); rxml_init_xinclude(); rxml_init_xpath(); rxml_init_xpath_object(); rxml_init_xpath_context(); rxml_init_xpath_expression(); rxml_init_html_parser(); rxml_init_html_parser_options(); rxml_init_html_parser_context(); rxml_init_input_callbacks(); rxml_init_dtd(); rxml_init_schema(); rxml_init_relaxng(); rxml_init_reader(); rxml_init_writer(); } libxml-ruby-5.0.3/ext/libxml/ruby_xml_relaxng.c0000644000004100000410000000576314620142101021633 0ustar www-datawww-data#include "ruby_libxml.h" #include "ruby_xml_relaxng.h" #include /* * Document-class: LibXML::XML::RelaxNG * * The XML::RelaxNG class is used to prepare RelaxNG schemas for validation * of xml documents. * * Schemas can be created from XML documents, strings or URIs using the * corresponding methods (new for URIs). * * Once a schema is prepared, an XML document can be validated by the * XML::Document#validate_relaxng method providing the XML::RelaxNG object * as parameter. The method will raise an exception if the document is * not valid. * * Basic Usage: * * # parse schema as xml document * relaxng_document = XML::Document.file('schema.rng') * * # prepare schema for validation * relaxng_schema = XML::RelaxNG.document(relaxng_document) * * # parse xml document to be validated * instance = XML::Document.file('instance.xml') * * # validate * instance.validate_relaxng(relaxng_schema) */ VALUE cXMLRelaxNG; static void rxml_relaxng_free(xmlRelaxNGPtr xrelaxng) { xmlRelaxNGFree(xrelaxng); } /* * call-seq: * XML::Relaxng.new(relaxng_uri) -> relaxng * * Create a new relaxng from the specified URI. */ static VALUE rxml_relaxng_init_from_uri(VALUE class, VALUE uri) { xmlRelaxNGParserCtxtPtr xparser; xmlRelaxNGPtr xrelaxng; Check_Type(uri, T_STRING); xparser = xmlRelaxNGNewParserCtxt(StringValuePtr(uri)); xrelaxng = xmlRelaxNGParse(xparser); xmlRelaxNGFreeParserCtxt(xparser); return Data_Wrap_Struct(cXMLRelaxNG, NULL, rxml_relaxng_free, xrelaxng); } /* * call-seq: * XML::RelaxNG.document(document) -> relaxng * * Create a new relaxng from the specified document. */ static VALUE rxml_relaxng_init_from_document(VALUE class, VALUE document) { xmlDocPtr xdoc; xmlRelaxNGPtr xrelaxng; xmlRelaxNGParserCtxtPtr xparser; Data_Get_Struct(document, xmlDoc, xdoc); xparser = xmlRelaxNGNewDocParserCtxt(xdoc); xrelaxng = xmlRelaxNGParse(xparser); xmlRelaxNGFreeParserCtxt(xparser); return Data_Wrap_Struct(cXMLRelaxNG, NULL, rxml_relaxng_free, xrelaxng); } /* * call-seq: * XML::RelaxNG.string("relaxng_data") -> "value" * * Create a new relaxng using the specified string. */ static VALUE rxml_relaxng_init_from_string(VALUE self, VALUE relaxng_str) { xmlRelaxNGParserCtxtPtr xparser; xmlRelaxNGPtr xrelaxng; Check_Type(relaxng_str, T_STRING); xparser = xmlRelaxNGNewMemParserCtxt(StringValuePtr(relaxng_str), (int)strlen(StringValuePtr(relaxng_str))); xrelaxng = xmlRelaxNGParse(xparser); xmlRelaxNGFreeParserCtxt(xparser); return Data_Wrap_Struct(cXMLRelaxNG, NULL, rxml_relaxng_free, xrelaxng); } void rxml_init_relaxng(void) { cXMLRelaxNG = rb_define_class_under(mXML, "RelaxNG", rb_cObject); rb_undef_alloc_func(cXMLRelaxNG); rb_define_singleton_method(cXMLRelaxNG, "new", rxml_relaxng_init_from_uri, 1); rb_define_singleton_method(cXMLRelaxNG, "from_string", rxml_relaxng_init_from_string, 1); rb_define_singleton_method(cXMLRelaxNG, "document", rxml_relaxng_init_from_document, 1); } libxml-ruby-5.0.3/ext/libxml/extconf.rb0000644000004100000410000000361214620142101020070 0ustar www-datawww-data#!/usr/bin/env ruby require 'mkmf' def crash(str) printf(" extconf failure: %s\n", str) exit 1 end xc = with_config('xml2-config') if xc cflags = `#{xc} --cflags`.chomp if $? != 0 cflags = nil else libs = `#{xc} --libs`.chomp if $? != 0 libs = nil else $CFLAGS += ' ' + cflags $libs = libs + " " + $libs end end else dir_config('xml2') end found_header = find_header('libxml/xmlversion.h', '/opt/include/libxml2', '/opt/local/include/libxml2', '/opt/homebrew/opt/libxml2/include/libxml2', '/usr/local/include/libxml2', '/usr/include/libxml2', '/usr/local/include', '/usr/local/opt/libxml2/include/libxml2') found_lib = find_library('xml2', 'xmlParseDoc', '/opt/lib', '/opt/local/lib', '/opt/homebrew/opt/libxml2/lib', '/usr/lib', '/usr/local/lib', '/usr/local/opt/libxml2/lib') found_lib ||= find_library('libxml2', 'xmlParseDoc', '/opt/lib', '/opt/local/lib', '/opt/homebrew/opt/libxml2/lib', '/usr/lib', '/usr/local/lib', '/usr/local/opt/libxml2/lib') if !found_header || !found_lib crash(<<~EOL) Cannot find libxml2. Install the library or try one of the following options to extconf.rb: --with-xml2-config=/path/to/xml2-config --with-xml2-dir=/path/to/libxml2 --with-xml2-lib=/path/to/libxml2/lib --with-xml2-include=/path/to/libxml2/include EOL end create_header() create_makefile('libxml_ruby') libxml-ruby-5.0.3/ext/libxml/ruby_xml_reader.h0000644000004100000410000000056514620142101021435 0ustar www-datawww-data/* Copyright (c) 2006 Apple Computer Inc. * Please see the LICENSE file for copyright and distribution information. */ #ifndef __RXML_READER__ #define __RXML_READER__ extern VALUE cXMLReader; void rxml_init_reader(void); /* Exported to be used by XML::Document#reader */ VALUE rxml_reader_new_walker(VALUE self, VALUE doc); #endif /* __rxml_READER__ */ libxml-ruby-5.0.3/ext/vc/0000755000004100000410000000000014620142101015214 5ustar www-datawww-datalibxml-ruby-5.0.3/ext/vc/libxml_ruby.sln0000644000004100000410000000243714620142101020270 0ustar www-datawww-data Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml_ruby", "libxml_ruby\libxml_ruby.vcxproj", "{0B65CD1D-EEB9-41AE-93BB-75496E504152}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0B65CD1D-EEB9-41AE-93BB-75496E504152}.Debug|x64.ActiveCfg = Debug|x64 {0B65CD1D-EEB9-41AE-93BB-75496E504152}.Debug|x64.Build.0 = Debug|x64 {0B65CD1D-EEB9-41AE-93BB-75496E504152}.Debug|x86.ActiveCfg = Debug|x64 {0B65CD1D-EEB9-41AE-93BB-75496E504152}.Debug|x86.Build.0 = Debug|x64 {0B65CD1D-EEB9-41AE-93BB-75496E504152}.Release|x64.ActiveCfg = Release|x64 {0B65CD1D-EEB9-41AE-93BB-75496E504152}.Release|x64.Build.0 = Release|x64 {0B65CD1D-EEB9-41AE-93BB-75496E504152}.Release|x86.ActiveCfg = Release|Win32 {0B65CD1D-EEB9-41AE-93BB-75496E504152}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal libxml-ruby-5.0.3/script/0000755000004100000410000000000014620142101015310 5ustar www-datawww-datalibxml-ruby-5.0.3/script/test0000644000004100000410000000017114620142101016211 0ustar www-datawww-data#!/usr/bin/env ruby %w{test lib ext/libxml}.each{ |path| $LOAD_PATH.unshift(path) } load './test/test_suite.rb' libxml-ruby-5.0.3/script/benchmark/0000755000004100000410000000000014620142101017242 5ustar www-datawww-datalibxml-ruby-5.0.3/script/benchmark/depixelate0000644000004100000410000005711114620142101021316 0ustar www-datawww-data#!/usr/bin/env ruby require 'rubygems' require 'benchmark' require 'hpricot' require 'rexml/document' require 'xml' # Taken from http://depixelate.com/2008/4/23/ruby-xml-parsing-benchmarks XML_STRING = DATA.read class Parse def self.libxml doc = XML::Parser.string(XML_STRING).parse ary = [] doc.find('/*/*/*').each do |node| case node.name when 'ItemQueryRs' node.each_element do |child| ary << child.find_first('./ListID') end end end ary end def self.rexml doc = REXML::Document.new(XML_STRING) ary = [] REXML::XPath.each(doc, '/*/*/*') do |node| case node.name when 'ItemQueryRs' node.elements.each do |element| ary << rexml_fetch(element, 'ListID') end end end ary end def self.hpricot doc = Hpricot.XML(XML_STRING) ary = [] response_element = doc.search('/*/*/*').each do |node| next unless node.elem? case node.name when 'ItemQueryRs' node.containers.each do |element| ary << hpricot_fetch(element/'ListID') end end end ary end # rexml helper def self.rexml_fetch(node, name) e = REXML::XPath.first(node, name) e ? e.text : nil end # hpricot helper def self.hpricot_fetch(path) return nil if path.nil? || path.empty? path = path.first if path.is_a?(Array) path.innerHTML end end TIMES = 10 Benchmark.bmbm do |x| x.report('libxml') { TIMES.times { Parse.libxml } } x.report('Hpricot') { TIMES.times { Parse.hpricot } } x.report('REXML') { TIMES.times { Parse.rexml } } end __END__ 240000-1071531214 2003-12-15T15:33:34-08:00 2003-12-15T15:34:51-08:00 1071531291 Delivery Delivery true 0 20000-999021789 Non Delivery Service Fee (free for orders over $100) 15.00 610001-1071531179 Service 10000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Design Design true 0 20000-999021789 Non Custom Landscape Design 55.00 150000-934380913 Landscaping Services:Design Services 20000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T08:59:12-08:00 934387152 Gardening Gardening true 0 20000-999021789 Non Weekly gardening services 0.00 1F0000-934380913 Landscaping Services:Labor:Installation 30000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Installation Installation true 0 20000-999021789 Non Installation of landscape design 35.00 1F0000-934380913 Landscaping Services:Labor:Installation 40000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Pest Control Pest Control true 0 20000-999021789 Non Pest control services 0.00 200000-934380913 Landscaping Services:Labor:Maintenance & Repairs 2E0000-1071514896 2003-12-15T11:01:36-08:00 2003-12-15T14:42:51-08:00 1071528171 Tree Removal Tree Removal true 0 20000-999021789 Non Tree Removal Service 0.00 610001-1071531179 Service 50000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Trimming Trimming true 0 20000-999021789 Non Tree and shrub trimming 35.00 200000-934380913 Landscaping Services:Labor:Maintenance & Repairs B0000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Concrete Concrete true 0 10000-999021789 Tax Concrete for fountain installation 0.00 1B0000-934380913 Landscaping Services:Job Materials:Fountains & Garden Lighting C0000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Deck Lumber Deck Lumber true 0 10000-999021789 Tax Deck Lumber 0.00 1A0000-934380913 Landscaping Services:Job Materials:Decks & Patios 210000-1071530240 2003-12-15T15:17:20-08:00 2003-12-15T15:17:20-08:00 1071530240 Fertilizer Fertilizer true 0 10000-999021789 Tax Parent Item - Do Not Use 0.00 600001-1071530232 Retail Sales 250000-1071523682 2003-12-15T13:28:02-08:00 2003-12-15T13:44:20-08:00 1071524660 Irrigation Hose Irrigation Hose true 0 10000-999021789 Tax Parent Item Vinyl Irrigation Line- Do Not Purchase or Sell 0.00 690001-1071523679 Landscaping Services:Job Materials:Misc Materials Vinyl Irrigation LineParent Item - Do Not Purchase or Sell 0.00 240000-934380913 Cost of Goods Sold 60000-934380912 Inventory Asset -1 0 0.00 0 0 270000-1071524193 2003-12-15T13:36:33-08:00 2003-12-15T13:38:13-08:00 1071524293 1/2" Line Irrigation Hose:1/2" Line true 250000-1071523682 Irrigation Hose 1 10000-999021789 Tax 1/2" Vinyl Irrigation Line 0.15 690001-1071523679 Landscaping Services:Job Materials:Misc Materials 1/2" Vinyl Irrigation Line 0.12 240000-934380913 Cost of Goods Sold 60000-934380912 Inventory Asset 1500 1783 0.12 0 0 260000-1071523858 2003-12-15T13:30:58-08:00 2003-12-15T13:37:52-08:00 1071524272 1/4" Line Irrigation Hose:1/4" Line true 250000-1071523682 Irrigation Hose 1 10000-999021789 Tax 1/4" Vinyl Irrigation Line 0.10 690001-1071523679 Landscaping Services:Job Materials:Misc Materials 1/4" Vinyl Irrigation Line 0.07 240000-934380913 Cost of Goods Sold 60000-934380912 Inventory Asset 500 1235 0.07 0 0 280000-1071524260 2003-12-15T13:37:40-08:00 2003-12-15T13:37:40-08:00 1071524260 3/4" Line Irrigation Hose:3/4" Line true 250000-1071523682 Irrigation Hose 1 10000-999021789 Tax 3/4" Vinyl Irrigation Line 0.27 690001-1071523679 Landscaping Services:Job Materials:Misc Materials 3/4" Vinyl Irrigation Line 0.18 240000-934380913 Cost of Goods Sold 60000-934380912 Inventory Asset 1500 2670 0.18 0 0 60000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Lighting Lighting true 0 10000-999021789 Tax Garden Lighting 0.00 1B0000-934380913 Landscaping Services:Job Materials:Fountains & Garden Lighting Garden Lighting 0.00 240000-934380913 Cost of Goods Sold 60000-934380912 Inventory Asset 94 14.80 28 0 70000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Pump Pump true 0 10000-999021789 Tax Fountain pump 75.00 1B0000-934380913 Landscaping Services:Job Materials:Fountains & Garden Lighting Fountain pump #198-30 56.00 240000-934380913 Cost of Goods Sold 60000-934380912 Inventory Asset 48 53.93 0 0 80000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Soil Soil true 0 10000-999021789 Tax Soil, 2 cubic ft bag 6.75 1C0000-934380913 Landscaping Services:Job Materials:Plants and Sod Soil, 2 cubic ft bag 5.30 240000-934380913 Cost of Goods Sold 10000-934380927 Middlefield Nursery 60000-934380912 Inventory Asset 25 0 5.30 6 10 90000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Sprinkler Hds Sprinkler Hds true 0 10000-999021789 Tax Sprinkler heads 0.00 1D0000-934380913 Landscaping Services:Job Materials:Sprinklers & Drip systems Sprinkler head #BLS9081-09 0.00 240000-934380913 Cost of Goods Sold 60000-934380912 Inventory Asset 69 6.38 36 0 A0000-934380927 1999-08-11T07:15:27-08:00 1999-08-11T07:15:27-08:00 934380927 Sprkl pipes Sprkl pipes true 0 10000-999021789 Tax Plastic sprinkler piping 2.75 1D0000-934380913 Landscaping Services:Job Materials:Sprinklers & Drip systems Plastic sprinkler piping #1098-20 2.10 240000-934380913 Cost of Goods Sold 60000-934380912 Inventory Asset 250 826 2.10 115 0 libxml-ruby-5.0.3/script/benchmark/sock_entries.xml0000644000004100000410000030124314620142101022457 0ustar www-datawww-data a0a5c490-b78e-11db-b2b3-0014c2c34555 http://saildataservice.concord.org/3/offering/1562/bundle/3693/1 libxml-ruby-5.0.3/script/benchmark/throughput0000644000004100000410000000162214620142101021377 0ustar www-datawww-data#!/usr/bin/env ruby require 'rubygems' require 'hpricot' require 'xml' require 'rexml/document' ITERATIONS = 3 NESTED_ITERATIONS = 5 def bm(name, filename, &block) text = File.open(filename).read length = text.length / 1024.0 / 1024.0 puts "#{filename}: #{name} (#{(length * 1024).round} kb)" for j in 0 .. NESTED_ITERATIONS s = Time.now.to_f for i in 0 .. ITERATIONS block.call(text) end timer = Time.now.to_f - s puts "\t#{length * ITERATIONS / timer} MB/s" end end def bm_suite(filenames) filenames.each do |filename| bm("LIBXML THROUGHPUT:", filename) do |text| XML::Document.file(filename) end bm("HPRICOT THROUGHPUT:", filename) do |text| Hpricot.XML(text) end bm("REXML THROUGHPUT:", filename) do |text| REXML::Document.new(text) end end end bm_suite("hamlet.xml") libxml-ruby-5.0.3/script/benchmark/hamlet.xml0000644000004100000410000106366414620142101021256 0ustar www-datawww-data The Tragedy of Hamlet, Prince of Denmark

ASCII text placed in the public domain by Moby Lexical Tools, 1992.

SGML markup by Jon Bosak, 1992-1994.

XML version by Jon Bosak, 1996-1999.

The XML markup in this version is Copyright © 1999 Jon Bosak. This work may freely be distributed on condition that it not be modified or altered in any way.

Dramatis Personae CLAUDIUS, king of Denmark. HAMLET, son to the late, and nephew to the present king. POLONIUS, lord chamberlain. HORATIO, friend to Hamlet. LAERTES, son to Polonius. LUCIANUS, nephew to the king. VOLTIMAND CORNELIUS ROSENCRANTZ GUILDENSTERN OSRIC courtiers. A Gentleman A Priest. MARCELLUS BERNARDO officers. FRANCISCO, a soldier. REYNALDO, servant to Polonius. Players. Two Clowns, grave-diggers. FORTINBRAS, prince of Norway. A Captain. English Ambassadors. GERTRUDE, queen of Denmark, and mother to Hamlet. OPHELIA, daughter to Polonius. Lords, Ladies, Officers, Soldiers, Sailors, Messengers, and other Attendants. Ghost of Hamlet's Father. SCENE Denmark. HAMLET ACT I SCENE I. Elsinore. A platform before the castle. FRANCISCO at his post. Enter to him BERNARDO BERNARDO Who's there? FRANCISCO Nay, answer me: stand, and unfold yourself. BERNARDO Long live the king! FRANCISCO Bernardo? BERNARDO He. FRANCISCO You come most carefully upon your hour. BERNARDO 'Tis now struck twelve; get thee to bed, Francisco. FRANCISCO For this relief much thanks: 'tis bitter cold, And I am sick at heart. BERNARDO Have you had quiet guard? FRANCISCO Not a mouse stirring. BERNARDO Well, good night. If you do meet Horatio and Marcellus, The rivals of my watch, bid them make haste. FRANCISCO I think I hear them. Stand, ho! Who's there? Enter HORATIO and MARCELLUS HORATIO Friends to this ground. MARCELLUS And liegemen to the Dane. FRANCISCO Give you good night. MARCELLUS O, farewell, honest soldier: Who hath relieved you? FRANCISCO Bernardo has my place. Give you good night. Exit MARCELLUS Holla! Bernardo! BERNARDO Say, What, is Horatio there? HORATIO A piece of him. BERNARDO Welcome, Horatio: welcome, good Marcellus. MARCELLUS What, has this thing appear'd again to-night? BERNARDO I have seen nothing. MARCELLUS Horatio says 'tis but our fantasy, And will not let belief take hold of him Touching this dreaded sight, twice seen of us: Therefore I have entreated him along With us to watch the minutes of this night; That if again this apparition come, He may approve our eyes and speak to it. HORATIO Tush, tush, 'twill not appear. BERNARDO Sit down awhile; And let us once again assail your ears, That are so fortified against our story What we have two nights seen. HORATIO Well, sit we down, And let us hear Bernardo speak of this. BERNARDO Last night of all, When yond same star that's westward from the pole Had made his course to illume that part of heaven Where now it burns, Marcellus and myself, The bell then beating one,-- Enter Ghost MARCELLUS Peace, break thee off; look, where it comes again! BERNARDO In the same figure, like the king that's dead. MARCELLUS Thou art a scholar; speak to it, Horatio. BERNARDO Looks it not like the king? mark it, Horatio. HORATIO Most like: it harrows me with fear and wonder. BERNARDO It would be spoke to. MARCELLUS Question it, Horatio. HORATIO What art thou that usurp'st this time of night, Together with that fair and warlike form In which the majesty of buried Denmark Did sometimes march? by heaven I charge thee, speak! MARCELLUS It is offended. BERNARDO See, it stalks away! HORATIO Stay! speak, speak! I charge thee, speak! Exit Ghost MARCELLUS 'Tis gone, and will not answer. BERNARDO How now, Horatio! you tremble and look pale: Is not this something more than fantasy? What think you on't? HORATIO Before my God, I might not this believe Without the sensible and true avouch Of mine own eyes. MARCELLUS Is it not like the king? HORATIO As thou art to thyself: Such was the very armour he had on When he the ambitious Norway combated; So frown'd he once, when, in an angry parle, He smote the sledded Polacks on the ice. 'Tis strange. MARCELLUS Thus twice before, and jump at this dead hour, With martial stalk hath he gone by our watch. HORATIO In what particular thought to work I know not; But in the gross and scope of my opinion, This bodes some strange eruption to our state. MARCELLUS Good now, sit down, and tell me, he that knows, Why this same strict and most observant watch So nightly toils the subject of the land, And why such daily cast of brazen cannon, And foreign mart for implements of war; Why such impress of shipwrights, whose sore task Does not divide the Sunday from the week; What might be toward, that this sweaty haste Doth make the night joint-labourer with the day: Who is't that can inform me? HORATIO That can I; At least, the whisper goes so. Our last king, Whose image even but now appear'd to us, Was, as you know, by Fortinbras of Norway, Thereto prick'd on by a most emulate pride, Dared to the combat; in which our valiant Hamlet-- For so this side of our known world esteem'd him-- Did slay this Fortinbras; who by a seal'd compact, Well ratified by law and heraldry, Did forfeit, with his life, all those his lands Which he stood seized of, to the conqueror: Against the which, a moiety competent Was gaged by our king; which had return'd To the inheritance of Fortinbras, Had he been vanquisher; as, by the same covenant, And carriage of the article design'd, His fell to Hamlet. Now, sir, young Fortinbras, Of unimproved mettle hot and full, Hath in the skirts of Norway here and there Shark'd up a list of lawless resolutes, For food and diet, to some enterprise That hath a stomach in't; which is no other-- As it doth well appear unto our state-- But to recover of us, by strong hand And terms compulsatory, those foresaid lands So by his father lost: and this, I take it, Is the main motive of our preparations, The source of this our watch and the chief head Of this post-haste and romage in the land. BERNARDO I think it be no other but e'en so: Well may it sort that this portentous figure Comes armed through our watch; so like the king That was and is the question of these wars. HORATIO A mote it is to trouble the mind's eye. In the most high and palmy state of Rome, A little ere the mightiest Julius fell, The graves stood tenantless and the sheeted dead Did squeak and gibber in the Roman streets: As stars with trains of fire and dews of blood, Disasters in the sun; and the moist star Upon whose influence Neptune's empire stands Was sick almost to doomsday with eclipse: And even the like precurse of fierce events, As harbingers preceding still the fates And prologue to the omen coming on, Have heaven and earth together demonstrated Unto our climatures and countrymen.-- But soft, behold! lo, where it comes again! Re-enter Ghost I'll cross it, though it blast me. Stay, illusion! If thou hast any sound, or use of voice, Speak to me: If there be any good thing to be done, That may to thee do ease and grace to me, Speak to me: Cock crows If thou art privy to thy country's fate, Which, happily, foreknowing may avoid, O, speak! Or if thou hast uphoarded in thy life Extorted treasure in the womb of earth, For which, they say, you spirits oft walk in death, Speak of it: stay, and speak! Stop it, Marcellus. MARCELLUS Shall I strike at it with my partisan? HORATIO Do, if it will not stand. BERNARDO 'Tis here! HORATIO 'Tis here! MARCELLUS 'Tis gone! Exit Ghost We do it wrong, being so majestical, To offer it the show of violence; For it is, as the air, invulnerable, And our vain blows malicious mockery. BERNARDO It was about to speak, when the cock crew. HORATIO And then it started like a guilty thing Upon a fearful summons. I have heard, The cock, that is the trumpet to the morn, Doth with his lofty and shrill-sounding throat Awake the god of day; and, at his warning, Whether in sea or fire, in earth or air, The extravagant and erring spirit hies To his confine: and of the truth herein This present object made probation. MARCELLUS It faded on the crowing of the cock. Some say that ever 'gainst that season comes Wherein our Saviour's birth is celebrated, The bird of dawning singeth all night long: And then, they say, no spirit dares stir abroad; The nights are wholesome; then no planets strike, No fairy takes, nor witch hath power to charm, So hallow'd and so gracious is the time. HORATIO So have I heard and do in part believe it. But, look, the morn, in russet mantle clad, Walks o'er the dew of yon high eastward hill: Break we our watch up; and by my advice, Let us impart what we have seen to-night Unto young Hamlet; for, upon my life, This spirit, dumb to us, will speak to him. Do you consent we shall acquaint him with it, As needful in our loves, fitting our duty? MARCELLUS Let's do't, I pray; and I this morning know Where we shall find him most conveniently. Exeunt SCENE II. A room of state in the castle. Enter KING CLAUDIUS, QUEEN GERTRUDE, HAMLET, POLONIUS, LAERTES, VOLTIMAND, CORNELIUS, Lords, and Attendants KING CLAUDIUS Though yet of Hamlet our dear brother's death The memory be green, and that it us befitted To bear our hearts in grief and our whole kingdom To be contracted in one brow of woe, Yet so far hath discretion fought with nature That we with wisest sorrow think on him, Together with remembrance of ourselves. Therefore our sometime sister, now our queen, The imperial jointress to this warlike state, Have we, as 'twere with a defeated joy,-- With an auspicious and a dropping eye, With mirth in funeral and with dirge in marriage, In equal scale weighing delight and dole,-- Taken to wife: nor have we herein barr'd Your better wisdoms, which have freely gone With this affair along. For all, our thanks. Now follows, that you know, young Fortinbras, Holding a weak supposal of our worth, Or thinking by our late dear brother's death Our state to be disjoint and out of frame, Colleagued with the dream of his advantage, He hath not fail'd to pester us with message, Importing the surrender of those lands Lost by his father, with all bonds of law, To our most valiant brother. So much for him. Now for ourself and for this time of meeting: Thus much the business is: we have here writ To Norway, uncle of young Fortinbras,-- Who, impotent and bed-rid, scarcely hears Of this his nephew's purpose,--to suppress His further gait herein; in that the levies, The lists and full proportions, are all made Out of his subject: and we here dispatch You, good Cornelius, and you, Voltimand, For bearers of this greeting to old Norway; Giving to you no further personal power To business with the king, more than the scope Of these delated articles allow. Farewell, and let your haste commend your duty. CORNELIUS VOLTIMAND In that and all things will we show our duty. KING CLAUDIUS We doubt it nothing: heartily farewell. Exeunt VOLTIMAND and CORNELIUS And now, Laertes, what's the news with you? You told us of some suit; what is't, Laertes? You cannot speak of reason to the Dane, And loose your voice: what wouldst thou beg, Laertes, That shall not be my offer, not thy asking? The head is not more native to the heart, The hand more instrumental to the mouth, Than is the throne of Denmark to thy father. What wouldst thou have, Laertes? LAERTES My dread lord, Your leave and favour to return to France; From whence though willingly I came to Denmark, To show my duty in your coronation, Yet now, I must confess, that duty done, My thoughts and wishes bend again toward France And bow them to your gracious leave and pardon. KING CLAUDIUS Have you your father's leave? What says Polonius? LORD POLONIUS He hath, my lord, wrung from me my slow leave By laboursome petition, and at last Upon his will I seal'd my hard consent: I do beseech you, give him leave to go. KING CLAUDIUS Take thy fair hour, Laertes; time be thine, And thy best graces spend it at thy will! But now, my cousin Hamlet, and my son,-- HAMLET Aside A little more than kin, and less than kind. KING CLAUDIUS How is it that the clouds still hang on you? HAMLET Not so, my lord; I am too much i' the sun. QUEEN GERTRUDE Good Hamlet, cast thy nighted colour off, And let thine eye look like a friend on Denmark. Do not for ever with thy vailed lids Seek for thy noble father in the dust: Thou know'st 'tis common; all that lives must die, Passing through nature to eternity. HAMLET Ay, madam, it is common. QUEEN GERTRUDE If it be, Why seems it so particular with thee? HAMLET Seems, madam! nay it is; I know not 'seems.' 'Tis not alone my inky cloak, good mother, Nor customary suits of solemn black, Nor windy suspiration of forced breath, No, nor the fruitful river in the eye, Nor the dejected 'havior of the visage, Together with all forms, moods, shapes of grief, That can denote me truly: these indeed seem, For they are actions that a man might play: But I have that within which passeth show; These but the trappings and the suits of woe. KING CLAUDIUS 'Tis sweet and commendable in your nature, Hamlet, To give these mourning duties to your father: But, you must know, your father lost a father; That father lost, lost his, and the survivor bound In filial obligation for some term To do obsequious sorrow: but to persever In obstinate condolement is a course Of impious stubbornness; 'tis unmanly grief; It shows a will most incorrect to heaven, A heart unfortified, a mind impatient, An understanding simple and unschool'd: For what we know must be and is as common As any the most vulgar thing to sense, Why should we in our peevish opposition Take it to heart? Fie! 'tis a fault to heaven, A fault against the dead, a fault to nature, To reason most absurd: whose common theme Is death of fathers, and who still hath cried, From the first corse till he that died to-day, 'This must be so.' We pray you, throw to earth This unprevailing woe, and think of us As of a father: for let the world take note, You are the most immediate to our throne; And with no less nobility of love Than that which dearest father bears his son, Do I impart toward you. For your intent In going back to school in Wittenberg, It is most retrograde to our desire: And we beseech you, bend you to remain Here, in the cheer and comfort of our eye, Our chiefest courtier, cousin, and our son. QUEEN GERTRUDE Let not thy mother lose her prayers, Hamlet: I pray thee, stay with us; go not to Wittenberg. HAMLET I shall in all my best obey you, madam. KING CLAUDIUS Why, 'tis a loving and a fair reply: Be as ourself in Denmark. Madam, come; This gentle and unforced accord of Hamlet Sits smiling to my heart: in grace whereof, No jocund health that Denmark drinks to-day, But the great cannon to the clouds shall tell, And the king's rouse the heavens all bruit again, Re-speaking earthly thunder. Come away. Exeunt all but HAMLET HAMLET O, that this too too solid flesh would melt Thaw and resolve itself into a dew! Or that the Everlasting had not fix'd His canon 'gainst self-slaughter! O God! God! How weary, stale, flat and unprofitable, Seem to me all the uses of this world! Fie on't! ah fie! 'tis an unweeded garden, That grows to seed; things rank and gross in nature Possess it merely. That it should come to this! But two months dead: nay, not so much, not two: So excellent a king; that was, to this, Hyperion to a satyr; so loving to my mother That he might not beteem the winds of heaven Visit her face too roughly. Heaven and earth! Must I remember? why, she would hang on him, As if increase of appetite had grown By what it fed on: and yet, within a month-- Let me not think on't--Frailty, thy name is woman!-- A little month, or ere those shoes were old With which she follow'd my poor father's body, Like Niobe, all tears:--why she, even she-- O, God! a beast, that wants discourse of reason, Would have mourn'd longer--married with my uncle, My father's brother, but no more like my father Than I to Hercules: within a month: Ere yet the salt of most unrighteous tears Had left the flushing in her galled eyes, She married. O, most wicked speed, to post With such dexterity to incestuous sheets! It is not nor it cannot come to good: But break, my heart; for I must hold my tongue. Enter HORATIO, MARCELLUS, and BERNARDO HORATIO Hail to your lordship! HAMLET I am glad to see you well: Horatio,--or I do forget myself. HORATIO The same, my lord, and your poor servant ever. HAMLET Sir, my good friend; I'll change that name with you: And what make you from Wittenberg, Horatio? Marcellus? MARCELLUS My good lord-- HAMLET I am very glad to see you. Good even, sir. But what, in faith, make you from Wittenberg? HORATIO A truant disposition, good my lord. HAMLET I would not hear your enemy say so, Nor shall you do mine ear that violence, To make it truster of your own report Against yourself: I know you are no truant. But what is your affair in Elsinore? We'll teach you to drink deep ere you depart. HORATIO My lord, I came to see your father's funeral. HAMLET I pray thee, do not mock me, fellow-student; I think it was to see my mother's wedding. HORATIO Indeed, my lord, it follow'd hard upon. HAMLET Thrift, thrift, Horatio! the funeral baked meats Did coldly furnish forth the marriage tables. Would I had met my dearest foe in heaven Or ever I had seen that day, Horatio! My father!--methinks I see my father. HORATIO Where, my lord? HAMLET In my mind's eye, Horatio. HORATIO I saw him once; he was a goodly king. HAMLET He was a man, take him for all in all, I shall not look upon his like again. HORATIO My lord, I think I saw him yesternight. HAMLET Saw? who? HORATIO My lord, the king your father. HAMLET The king my father! HORATIO Season your admiration for awhile With an attent ear, till I may deliver, Upon the witness of these gentlemen, This marvel to you. HAMLET For God's love, let me hear. HORATIO Two nights together had these gentlemen, Marcellus and Bernardo, on their watch, In the dead vast and middle of the night, Been thus encounter'd. A figure like your father, Armed at point exactly, cap-a-pe, Appears before them, and with solemn march Goes slow and stately by them: thrice he walk'd By their oppress'd and fear-surprised eyes, Within his truncheon's length; whilst they, distilled Almost to jelly with the act of fear, Stand dumb and speak not to him. This to me In dreadful secrecy impart they did; And I with them the third night kept the watch; Where, as they had deliver'd, both in time, Form of the thing, each word made true and good, The apparition comes: I knew your father; These hands are not more like. HAMLET But where was this? MARCELLUS My lord, upon the platform where we watch'd. HAMLET Did you not speak to it? HORATIO My lord, I did; But answer made it none: yet once methought It lifted up its head and did address Itself to motion, like as it would speak; But even then the morning cock crew loud, And at the sound it shrunk in haste away, And vanish'd from our sight. HAMLET 'Tis very strange. HORATIO As I do live, my honour'd lord, 'tis true; And we did think it writ down in our duty To let you know of it. HAMLET Indeed, indeed, sirs, but this troubles me. Hold you the watch to-night? MARCELLUS BERNARDO We do, my lord. HAMLET Arm'd, say you? MARCELLUS BERNARDO Arm'd, my lord. HAMLET From top to toe? MARCELLUS BERNARDO My lord, from head to foot. HAMLET Then saw you not his face? HORATIO O, yes, my lord; he wore his beaver up. HAMLET What, look'd he frowningly? HORATIO A countenance more in sorrow than in anger. HAMLET Pale or red? HORATIO Nay, very pale. HAMLET And fix'd his eyes upon you? HORATIO Most constantly. HAMLET I would I had been there. HORATIO It would have much amazed you. HAMLET Very like, very like. Stay'd it long? HORATIO While one with moderate haste might tell a hundred. MARCELLUS BERNARDO Longer, longer. HORATIO Not when I saw't. HAMLET His beard was grizzled--no? HORATIO It was, as I have seen it in his life, A sable silver'd. HAMLET I will watch to-night; Perchance 'twill walk again. HORATIO I warrant it will. HAMLET If it assume my noble father's person, I'll speak to it, though hell itself should gape And bid me hold my peace. I pray you all, If you have hitherto conceal'd this sight, Let it be tenable in your silence still; And whatsoever else shall hap to-night, Give it an understanding, but no tongue: I will requite your loves. So, fare you well: Upon the platform, 'twixt eleven and twelve, I'll visit you. All Our duty to your honour. HAMLET Your loves, as mine to you: farewell. Exeunt all but HAMLET My father's spirit in arms! all is not well; I doubt some foul play: would the night were come! Till then sit still, my soul: foul deeds will rise, Though all the earth o'erwhelm them, to men's eyes. Exit SCENE III. A room in Polonius' house. Enter LAERTES and OPHELIA LAERTES My necessaries are embark'd: farewell: And, sister, as the winds give benefit And convoy is assistant, do not sleep, But let me hear from you. OPHELIA Do you doubt that? LAERTES For Hamlet and the trifling of his favour, Hold it a fashion and a toy in blood, A violet in the youth of primy nature, Forward, not permanent, sweet, not lasting, The perfume and suppliance of a minute; No more. OPHELIA No more but so? LAERTES Think it no more; For nature, crescent, does not grow alone In thews and bulk, but, as this temple waxes, The inward service of the mind and soul Grows wide withal. Perhaps he loves you now, And now no soil nor cautel doth besmirch The virtue of his will: but you must fear, His greatness weigh'd, his will is not his own; For he himself is subject to his birth: He may not, as unvalued persons do, Carve for himself; for on his choice depends The safety and health of this whole state; And therefore must his choice be circumscribed Unto the voice and yielding of that body Whereof he is the head. Then if he says he loves you, It fits your wisdom so far to believe it As he in his particular act and place May give his saying deed; which is no further Than the main voice of Denmark goes withal. Then weigh what loss your honour may sustain, If with too credent ear you list his songs, Or lose your heart, or your chaste treasure open To his unmaster'd importunity. Fear it, Ophelia, fear it, my dear sister, And keep you in the rear of your affection, Out of the shot and danger of desire. The chariest maid is prodigal enough, If she unmask her beauty to the moon: Virtue itself 'scapes not calumnious strokes: The canker galls the infants of the spring, Too oft before their buttons be disclosed, And in the morn and liquid dew of youth Contagious blastments are most imminent. Be wary then; best safety lies in fear: Youth to itself rebels, though none else near. OPHELIA I shall the effect of this good lesson keep, As watchman to my heart. But, good my brother, Do not, as some ungracious pastors do, Show me the steep and thorny way to heaven; Whiles, like a puff'd and reckless libertine, Himself the primrose path of dalliance treads, And recks not his own rede. LAERTES O, fear me not. I stay too long: but here my father comes. Enter POLONIUS A double blessing is a double grace, Occasion smiles upon a second leave. LORD POLONIUS Yet here, Laertes! aboard, aboard, for shame! The wind sits in the shoulder of your sail, And you are stay'd for. There; my blessing with thee! And these few precepts in thy memory See thou character. Give thy thoughts no tongue, Nor any unproportioned thought his act. Be thou familiar, but by no means vulgar. Those friends thou hast, and their adoption tried, Grapple them to thy soul with hoops of steel; But do not dull thy palm with entertainment Of each new-hatch'd, unfledged comrade. Beware Of entrance to a quarrel, but being in, Bear't that the opposed may beware of thee. Give every man thy ear, but few thy voice; Take each man's censure, but reserve thy judgment. Costly thy habit as thy purse can buy, But not express'd in fancy; rich, not gaudy; For the apparel oft proclaims the man, And they in France of the best rank and station Are of a most select and generous chief in that. Neither a borrower nor a lender be; For loan oft loses both itself and friend, And borrowing dulls the edge of husbandry. This above all: to thine ownself be true, And it must follow, as the night the day, Thou canst not then be false to any man. Farewell: my blessing season this in thee! LAERTES Most humbly do I take my leave, my lord. LORD POLONIUS The time invites you; go; your servants tend. LAERTES Farewell, Ophelia; and remember well What I have said to you. OPHELIA 'Tis in my memory lock'd, And you yourself shall keep the key of it. LAERTES Farewell. Exit LORD POLONIUS What is't, Ophelia, be hath said to you? OPHELIA So please you, something touching the Lord Hamlet. LORD POLONIUS Marry, well bethought: 'Tis told me, he hath very oft of late Given private time to you; and you yourself Have of your audience been most free and bounteous: If it be so, as so 'tis put on me, And that in way of caution, I must tell you, You do not understand yourself so clearly As it behoves my daughter and your honour. What is between you? give me up the truth. OPHELIA He hath, my lord, of late made many tenders Of his affection to me. LORD POLONIUS Affection! pooh! you speak like a green girl, Unsifted in such perilous circumstance. Do you believe his tenders, as you call them? OPHELIA I do not know, my lord, what I should think. LORD POLONIUS Marry, I'll teach you: think yourself a baby; That you have ta'en these tenders for true pay, Which are not sterling. Tender yourself more dearly; Or--not to crack the wind of the poor phrase, Running it thus--you'll tender me a fool. OPHELIA My lord, he hath importuned me with love In honourable fashion. LORD POLONIUS Ay, fashion you may call it; go to, go to. OPHELIA And hath given countenance to his speech, my lord, With almost all the holy vows of heaven. LORD POLONIUS Ay, springes to catch woodcocks. I do know, When the blood burns, how prodigal the soul Lends the tongue vows: these blazes, daughter, Giving more light than heat, extinct in both, Even in their promise, as it is a-making, You must not take for fire. From this time Be somewhat scanter of your maiden presence; Set your entreatments at a higher rate Than a command to parley. For Lord Hamlet, Believe so much in him, that he is young And with a larger tether may he walk Than may be given you: in few, Ophelia, Do not believe his vows; for they are brokers, Not of that dye which their investments show, But mere implorators of unholy suits, Breathing like sanctified and pious bawds, The better to beguile. This is for all: I would not, in plain terms, from this time forth, Have you so slander any moment leisure, As to give words or talk with the Lord Hamlet. Look to't, I charge you: come your ways. OPHELIA I shall obey, my lord. Exeunt SCENE IV. The platform. Enter HAMLET, HORATIO, and MARCELLUS HAMLET The air bites shrewdly; it is very cold. HORATIO It is a nipping and an eager air. HAMLET What hour now? HORATIO I think it lacks of twelve. HAMLET No, it is struck. HORATIO Indeed? I heard it not: then it draws near the season Wherein the spirit held his wont to walk. A flourish of trumpets, and ordnance shot off, within What does this mean, my lord? HAMLET The king doth wake to-night and takes his rouse, Keeps wassail, and the swaggering up-spring reels; And, as he drains his draughts of Rhenish down, The kettle-drum and trumpet thus bray out The triumph of his pledge. HORATIO Is it a custom? HAMLET Ay, marry, is't: But to my mind, though I am native here And to the manner born, it is a custom More honour'd in the breach than the observance. This heavy-headed revel east and west Makes us traduced and tax'd of other nations: They clepe us drunkards, and with swinish phrase Soil our addition; and indeed it takes From our achievements, though perform'd at height, The pith and marrow of our attribute. So, oft it chances in particular men, That for some vicious mole of nature in them, As, in their birth--wherein they are not guilty, Since nature cannot choose his origin-- By the o'ergrowth of some complexion, Oft breaking down the pales and forts of reason, Or by some habit that too much o'er-leavens The form of plausive manners, that these men, Carrying, I say, the stamp of one defect, Being nature's livery, or fortune's star,-- Their virtues else--be they as pure as grace, As infinite as man may undergo-- Shall in the general censure take corruption From that particular fault: the dram of eale Doth all the noble substance of a doubt To his own scandal. HORATIO Look, my lord, it comes! Enter Ghost HAMLET Angels and ministers of grace defend us! Be thou a spirit of health or goblin damn'd, Bring with thee airs from heaven or blasts from hell, Be thy intents wicked or charitable, Thou comest in such a questionable shape That I will speak to thee: I'll call thee Hamlet, King, father, royal Dane: O, answer me! Let me not burst in ignorance; but tell Why thy canonized bones, hearsed in death, Have burst their cerements; why the sepulchre, Wherein we saw thee quietly inurn'd, Hath oped his ponderous and marble jaws, To cast thee up again. What may this mean, That thou, dead corse, again in complete steel Revisit'st thus the glimpses of the moon, Making night hideous; and we fools of nature So horridly to shake our disposition With thoughts beyond the reaches of our souls? Say, why is this? wherefore? what should we do? Ghost beckons HAMLET HORATIO It beckons you to go away with it, As if it some impartment did desire To you alone. MARCELLUS Look, with what courteous action It waves you to a more removed ground: But do not go with it. HORATIO No, by no means. HAMLET It will not speak; then I will follow it. HORATIO Do not, my lord. HAMLET Why, what should be the fear? I do not set my life in a pin's fee; And for my soul, what can it do to that, Being a thing immortal as itself? It waves me forth again: I'll follow it. HORATIO What if it tempt you toward the flood, my lord, Or to the dreadful summit of the cliff That beetles o'er his base into the sea, And there assume some other horrible form, Which might deprive your sovereignty of reason And draw you into madness? think of it: The very place puts toys of desperation, Without more motive, into every brain That looks so many fathoms to the sea And hears it roar beneath. HAMLET It waves me still. Go on; I'll follow thee. MARCELLUS You shall not go, my lord. HAMLET Hold off your hands. HORATIO Be ruled; you shall not go. HAMLET My fate cries out, And makes each petty artery in this body As hardy as the Nemean lion's nerve. Still am I call'd. Unhand me, gentlemen. By heaven, I'll make a ghost of him that lets me! I say, away! Go on; I'll follow thee. Exeunt Ghost and HAMLET HORATIO He waxes desperate with imagination. MARCELLUS Let's follow; 'tis not fit thus to obey him. HORATIO Have after. To what issue will this come? MARCELLUS Something is rotten in the state of Denmark. HORATIO Heaven will direct it. MARCELLUS Nay, let's follow him. Exeunt SCENE V. Another part of the platform. Enter GHOST and HAMLET HAMLET Where wilt thou lead me? speak; I'll go no further. Ghost Mark me. HAMLET I will. Ghost My hour is almost come, When I to sulphurous and tormenting flames Must render up myself. HAMLET Alas, poor ghost! Ghost Pity me not, but lend thy serious hearing To what I shall unfold. HAMLET Speak; I am bound to hear. Ghost So art thou to revenge, when thou shalt hear. HAMLET What? Ghost I am thy father's spirit, Doom'd for a certain term to walk the night, And for the day confined to fast in fires, Till the foul crimes done in my days of nature Are burnt and purged away. But that I am forbid To tell the secrets of my prison-house, I could a tale unfold whose lightest word Would harrow up thy soul, freeze thy young blood, Make thy two eyes, like stars, start from their spheres, Thy knotted and combined locks to part And each particular hair to stand on end, Like quills upon the fretful porpentine: But this eternal blazon must not be To ears of flesh and blood. List, list, O, list! If thou didst ever thy dear father love-- HAMLET O God! Ghost Revenge his foul and most unnatural murder. HAMLET Murder! Ghost Murder most foul, as in the best it is; But this most foul, strange and unnatural. HAMLET Haste me to know't, that I, with wings as swift As meditation or the thoughts of love, May sweep to my revenge. Ghost I find thee apt; And duller shouldst thou be than the fat weed That roots itself in ease on Lethe wharf, Wouldst thou not stir in this. Now, Hamlet, hear: 'Tis given out that, sleeping in my orchard, A serpent stung me; so the whole ear of Denmark Is by a forged process of my death Rankly abused: but know, thou noble youth, The serpent that did sting thy father's life Now wears his crown. HAMLET O my prophetic soul! My uncle! Ghost Ay, that incestuous, that adulterate beast, With witchcraft of his wit, with traitorous gifts,-- O wicked wit and gifts, that have the power So to seduce!--won to his shameful lust The will of my most seeming-virtuous queen: O Hamlet, what a falling-off was there! From me, whose love was of that dignity That it went hand in hand even with the vow I made to her in marriage, and to decline Upon a wretch whose natural gifts were poor To those of mine! But virtue, as it never will be moved, Though lewdness court it in a shape of heaven, So lust, though to a radiant angel link'd, Will sate itself in a celestial bed, And prey on garbage. But, soft! methinks I scent the morning air; Brief let me be. Sleeping within my orchard, My custom always of the afternoon, Upon my secure hour thy uncle stole, With juice of cursed hebenon in a vial, And in the porches of my ears did pour The leperous distilment; whose effect Holds such an enmity with blood of man That swift as quicksilver it courses through The natural gates and alleys of the body, And with a sudden vigour doth posset And curd, like eager droppings into milk, The thin and wholesome blood: so did it mine; And a most instant tetter bark'd about, Most lazar-like, with vile and loathsome crust, All my smooth body. Thus was I, sleeping, by a brother's hand Of life, of crown, of queen, at once dispatch'd: Cut off even in the blossoms of my sin, Unhousel'd, disappointed, unanel'd, No reckoning made, but sent to my account With all my imperfections on my head: O, horrible! O, horrible! most horrible! If thou hast nature in thee, bear it not; Let not the royal bed of Denmark be A couch for luxury and damned incest. But, howsoever thou pursuest this act, Taint not thy mind, nor let thy soul contrive Against thy mother aught: leave her to heaven And to those thorns that in her bosom lodge, To prick and sting her. Fare thee well at once! The glow-worm shows the matin to be near, And 'gins to pale his uneffectual fire: Adieu, adieu! Hamlet, remember me. Exit HAMLET O all you host of heaven! O earth! what else? And shall I couple hell? O, fie! Hold, hold, my heart; And you, my sinews, grow not instant old, But bear me stiffly up. Remember thee! Ay, thou poor ghost, while memory holds a seat In this distracted globe. Remember thee! Yea, from the table of my memory I'll wipe away all trivial fond records, All saws of books, all forms, all pressures past, That youth and observation copied there; And thy commandment all alone shall live Within the book and volume of my brain, Unmix'd with baser matter: yes, by heaven! O most pernicious woman! O villain, villain, smiling, damned villain! My tables,--meet it is I set it down, That one may smile, and smile, and be a villain; At least I'm sure it may be so in Denmark: Writing So, uncle, there you are. Now to my word; It is 'Adieu, adieu! remember me.' I have sworn 't. MARCELLUS HORATIO Within My lord, my lord,-- MARCELLUS Within Lord Hamlet,-- HORATIO Within Heaven secure him! HAMLET So be it! HORATIO Within Hillo, ho, ho, my lord! HAMLET Hillo, ho, ho, boy! come, bird, come. Enter HORATIO and MARCELLUS MARCELLUS How is't, my noble lord? HORATIO What news, my lord? HAMLET O, wonderful! HORATIO Good my lord, tell it. HAMLET No; you'll reveal it. HORATIO Not I, my lord, by heaven. MARCELLUS Nor I, my lord. HAMLET How say you, then; would heart of man once think it? But you'll be secret? HORATIO MARCELLUS Ay, by heaven, my lord. HAMLET There's ne'er a villain dwelling in all Denmark But he's an arrant knave. HORATIO There needs no ghost, my lord, come from the grave To tell us this. HAMLET Why, right; you are i' the right; And so, without more circumstance at all, I hold it fit that we shake hands and part: You, as your business and desire shall point you; For every man has business and desire, Such as it is; and for mine own poor part, Look you, I'll go pray. HORATIO These are but wild and whirling words, my lord. HAMLET I'm sorry they offend you, heartily; Yes, 'faith heartily. HORATIO There's no offence, my lord. HAMLET Yes, by Saint Patrick, but there is, Horatio, And much offence too. Touching this vision here, It is an honest ghost, that let me tell you: For your desire to know what is between us, O'ermaster 't as you may. And now, good friends, As you are friends, scholars and soldiers, Give me one poor request. HORATIO What is't, my lord? we will. HAMLET Never make known what you have seen to-night. HORATIO MARCELLUS My lord, we will not. HAMLET Nay, but swear't. HORATIO In faith, My lord, not I. MARCELLUS Nor I, my lord, in faith. HAMLET Upon my sword. MARCELLUS We have sworn, my lord, already. HAMLET Indeed, upon my sword, indeed. Ghost Beneath Swear. HAMLET Ah, ha, boy! say'st thou so? art thou there, truepenny? Come on--you hear this fellow in the cellarage-- Consent to swear. HORATIO Propose the oath, my lord. HAMLET Never to speak of this that you have seen, Swear by my sword. Ghost Beneath Swear. HAMLET Hic et ubique? then we'll shift our ground. Come hither, gentlemen, And lay your hands again upon my sword: Never to speak of this that you have heard, Swear by my sword. Ghost Beneath Swear. HAMLET Well said, old mole! canst work i' the earth so fast? A worthy pioner! Once more remove, good friends. HORATIO O day and night, but this is wondrous strange! HAMLET And therefore as a stranger give it welcome. There are more things in heaven and earth, Horatio, Than are dreamt of in your philosophy. But come; Here, as before, never, so help you mercy, How strange or odd soe'er I bear myself, As I perchance hereafter shall think meet To put an antic disposition on, That you, at such times seeing me, never shall, With arms encumber'd thus, or this headshake, Or by pronouncing of some doubtful phrase, As 'Well, well, we know,' or 'We could, an if we would,' Or 'If we list to speak,' or 'There be, an if they might,' Or such ambiguous giving out, to note That you know aught of me: this not to do, So grace and mercy at your most need help you, Swear. Ghost Beneath Swear. HAMLET Rest, rest, perturbed spirit! They swear So, gentlemen, With all my love I do commend me to you: And what so poor a man as Hamlet is May do, to express his love and friending to you, God willing, shall not lack. Let us go in together; And still your fingers on your lips, I pray. The time is out of joint: O cursed spite, That ever I was born to set it right! Nay, come, let's go together. Exeunt ACT II SCENE I. A room in POLONIUS' house. Enter POLONIUS and REYNALDO LORD POLONIUS Give him this money and these notes, Reynaldo. REYNALDO I will, my lord. LORD POLONIUS You shall do marvellous wisely, good Reynaldo, Before you visit him, to make inquire Of his behavior. REYNALDO My lord, I did intend it. LORD POLONIUS Marry, well said; very well said. Look you, sir, Inquire me first what Danskers are in Paris; And how, and who, what means, and where they keep, What company, at what expense; and finding By this encompassment and drift of question That they do know my son, come you more nearer Than your particular demands will touch it: Take you, as 'twere, some distant knowledge of him; As thus, 'I know his father and his friends, And in part him: ' do you mark this, Reynaldo? REYNALDO Ay, very well, my lord. LORD POLONIUS 'And in part him; but' you may say 'not well: But, if't be he I mean, he's very wild; Addicted so and so:' and there put on him What forgeries you please; marry, none so rank As may dishonour him; take heed of that; But, sir, such wanton, wild and usual slips As are companions noted and most known To youth and liberty. REYNALDO As gaming, my lord. LORD POLONIUS Ay, or drinking, fencing, swearing, quarrelling, Drabbing: you may go so far. REYNALDO My lord, that would dishonour him. LORD POLONIUS 'Faith, no; as you may season it in the charge You must not put another scandal on him, That he is open to incontinency; That's not my meaning: but breathe his faults so quaintly That they may seem the taints of liberty, The flash and outbreak of a fiery mind, A savageness in unreclaimed blood, Of general assault. REYNALDO But, my good lord,-- LORD POLONIUS Wherefore should you do this? REYNALDO Ay, my lord, I would know that. LORD POLONIUS Marry, sir, here's my drift; And I believe, it is a fetch of wit: You laying these slight sullies on my son, As 'twere a thing a little soil'd i' the working, Mark you, Your party in converse, him you would sound, Having ever seen in the prenominate crimes The youth you breathe of guilty, be assured He closes with you in this consequence; 'Good sir,' or so, or 'friend,' or 'gentleman,' According to the phrase or the addition Of man and country. REYNALDO Very good, my lord. LORD POLONIUS And then, sir, does he this--he does--what was I about to say? By the mass, I was about to say something: where did I leave? REYNALDO At 'closes in the consequence,' at 'friend or so,' and 'gentleman.' LORD POLONIUS At 'closes in the consequence,' ay, marry; He closes thus: 'I know the gentleman; I saw him yesterday, or t' other day, Or then, or then; with such, or such; and, as you say, There was a' gaming; there o'ertook in's rouse; There falling out at tennis:' or perchance, 'I saw him enter such a house of sale,' Videlicet, a brothel, or so forth. See you now; Your bait of falsehood takes this carp of truth: And thus do we of wisdom and of reach, With windlasses and with assays of bias, By indirections find directions out: So by my former lecture and advice, Shall you my son. You have me, have you not? REYNALDO My lord, I have. LORD POLONIUS God be wi' you; fare you well. REYNALDO Good my lord! LORD POLONIUS Observe his inclination in yourself. REYNALDO I shall, my lord. LORD POLONIUS And let him ply his music. REYNALDO Well, my lord. LORD POLONIUS Farewell! Exit REYNALDO Enter OPHELIA How now, Ophelia! what's the matter? OPHELIA O, my lord, my lord, I have been so affrighted! LORD POLONIUS With what, i' the name of God? OPHELIA My lord, as I was sewing in my closet, Lord Hamlet, with his doublet all unbraced; No hat upon his head; his stockings foul'd, Ungarter'd, and down-gyved to his ancle; Pale as his shirt; his knees knocking each other; And with a look so piteous in purport As if he had been loosed out of hell To speak of horrors,--he comes before me. LORD POLONIUS Mad for thy love? OPHELIA My lord, I do not know; But truly, I do fear it. LORD POLONIUS What said he? OPHELIA He took me by the wrist and held me hard; Then goes he to the length of all his arm; And, with his other hand thus o'er his brow, He falls to such perusal of my face As he would draw it. Long stay'd he so; At last, a little shaking of mine arm And thrice his head thus waving up and down, He raised a sigh so piteous and profound As it did seem to shatter all his bulk And end his being: that done, he lets me go: And, with his head over his shoulder turn'd, He seem'd to find his way without his eyes; For out o' doors he went without their helps, And, to the last, bended their light on me. LORD POLONIUS Come, go with me: I will go seek the king. This is the very ecstasy of love, Whose violent property fordoes itself And leads the will to desperate undertakings As oft as any passion under heaven That does afflict our natures. I am sorry. What, have you given him any hard words of late? OPHELIA No, my good lord, but, as you did command, I did repel his fetters and denied His access to me. LORD POLONIUS That hath made him mad. I am sorry that with better heed and judgment I had not quoted him: I fear'd he did but trifle, And meant to wreck thee; but, beshrew my jealousy! By heaven, it is as proper to our age To cast beyond ourselves in our opinions As it is common for the younger sort To lack discretion. Come, go we to the king: This must be known; which, being kept close, might move More grief to hide than hate to utter love. Exeunt SCENE II. A room in the castle. Enter KING CLAUDIUS, QUEEN GERTRUDE, ROSENCRANTZ, GUILDENSTERN, and Attendants KING CLAUDIUS Welcome, dear Rosencrantz and Guildenstern! Moreover that we much did long to see you, The need we have to use you did provoke Our hasty sending. Something have you heard Of Hamlet's transformation; so call it, Sith nor the exterior nor the inward man Resembles that it was. What it should be, More than his father's death, that thus hath put him So much from the understanding of himself, I cannot dream of: I entreat you both, That, being of so young days brought up with him, And sith so neighbour'd to his youth and havior, That you vouchsafe your rest here in our court Some little time: so by your companies To draw him on to pleasures, and to gather, So much as from occasion you may glean, Whether aught, to us unknown, afflicts him thus, That, open'd, lies within our remedy. QUEEN GERTRUDE Good gentlemen, he hath much talk'd of you; And sure I am two men there are not living To whom he more adheres. If it will please you To show us so much gentry and good will As to expend your time with us awhile, For the supply and profit of our hope, Your visitation shall receive such thanks As fits a king's remembrance. ROSENCRANTZ Both your majesties Might, by the sovereign power you have of us, Put your dread pleasures more into command Than to entreaty. GUILDENSTERN But we both obey, And here give up ourselves, in the full bent To lay our service freely at your feet, To be commanded. KING CLAUDIUS Thanks, Rosencrantz and gentle Guildenstern. QUEEN GERTRUDE Thanks, Guildenstern and gentle Rosencrantz: And I beseech you instantly to visit My too much changed son. Go, some of you, And bring these gentlemen where Hamlet is. GUILDENSTERN Heavens make our presence and our practises Pleasant and helpful to him! QUEEN GERTRUDE Ay, amen! Exeunt ROSENCRANTZ, GUILDENSTERN, and some Attendants Enter POLONIUS LORD POLONIUS The ambassadors from Norway, my good lord, Are joyfully return'd. KING CLAUDIUS Thou still hast been the father of good news. LORD POLONIUS Have I, my lord? I assure my good liege, I hold my duty, as I hold my soul, Both to my God and to my gracious king: And I do think, or else this brain of mine Hunts not the trail of policy so sure As it hath used to do, that I have found The very cause of Hamlet's lunacy. KING CLAUDIUS O, speak of that; that do I long to hear. LORD POLONIUS Give first admittance to the ambassadors; My news shall be the fruit to that great feast. KING CLAUDIUS Thyself do grace to them, and bring them in. Exit POLONIUS He tells me, my dear Gertrude, he hath found The head and source of all your son's distemper. QUEEN GERTRUDE I doubt it is no other but the main; His father's death, and our o'erhasty marriage. KING CLAUDIUS Well, we shall sift him. Re-enter POLONIUS, with VOLTIMAND and CORNELIUS Welcome, my good friends! Say, Voltimand, what from our brother Norway? VOLTIMAND Most fair return of greetings and desires. Upon our first, he sent out to suppress His nephew's levies; which to him appear'd To be a preparation 'gainst the Polack; But, better look'd into, he truly found It was against your highness: whereat grieved, That so his sickness, age and impotence Was falsely borne in hand, sends out arrests On Fortinbras; which he, in brief, obeys; Receives rebuke from Norway, and in fine Makes vow before his uncle never more To give the assay of arms against your majesty. Whereon old Norway, overcome with joy, Gives him three thousand crowns in annual fee, And his commission to employ those soldiers, So levied as before, against the Polack: With an entreaty, herein further shown, Giving a paper That it might please you to give quiet pass Through your dominions for this enterprise, On such regards of safety and allowance As therein are set down. KING CLAUDIUS It likes us well; And at our more consider'd time well read, Answer, and think upon this business. Meantime we thank you for your well-took labour: Go to your rest; at night we'll feast together: Most welcome home! Exeunt VOLTIMAND and CORNELIUS LORD POLONIUS This business is well ended. My liege, and madam, to expostulate What majesty should be, what duty is, Why day is day, night night, and time is time, Were nothing but to waste night, day and time. Therefore, since brevity is the soul of wit, And tediousness the limbs and outward flourishes, I will be brief: your noble son is mad: Mad call I it; for, to define true madness, What is't but to be nothing else but mad? But let that go. QUEEN GERTRUDE More matter, with less art. LORD POLONIUS Madam, I swear I use no art at all. That he is mad, 'tis true: 'tis true 'tis pity; And pity 'tis 'tis true: a foolish figure; But farewell it, for I will use no art. Mad let us grant him, then: and now remains That we find out the cause of this effect, Or rather say, the cause of this defect, For this effect defective comes by cause: Thus it remains, and the remainder thus. Perpend. I have a daughter--have while she is mine-- Who, in her duty and obedience, mark, Hath given me this: now gather, and surmise. Reads 'To the celestial and my soul's idol, the most beautified Ophelia,'-- That's an ill phrase, a vile phrase; 'beautified' is a vile phrase: but you shall hear. Thus: Reads 'In her excellent white bosom, these, &c.' QUEEN GERTRUDE Came this from Hamlet to her? LORD POLONIUS Good madam, stay awhile; I will be faithful. Reads 'Doubt thou the stars are fire; Doubt that the sun doth move; Doubt truth to be a liar; But never doubt I love. 'O dear Ophelia, I am ill at these numbers; I have not art to reckon my groans: but that I love thee best, O most best, believe it. Adieu. 'Thine evermore most dear lady, whilst this machine is to him, HAMLET.' This, in obedience, hath my daughter shown me, And more above, hath his solicitings, As they fell out by time, by means and place, All given to mine ear. KING CLAUDIUS But how hath she Received his love? LORD POLONIUS What do you think of me? KING CLAUDIUS As of a man faithful and honourable. LORD POLONIUS I would fain prove so. But what might you think, When I had seen this hot love on the wing-- As I perceived it, I must tell you that, Before my daughter told me--what might you, Or my dear majesty your queen here, think, If I had play'd the desk or table-book, Or given my heart a winking, mute and dumb, Or look'd upon this love with idle sight; What might you think? No, I went round to work, And my young mistress thus I did bespeak: 'Lord Hamlet is a prince, out of thy star; This must not be:' and then I precepts gave her, That she should lock herself from his resort, Admit no messengers, receive no tokens. Which done, she took the fruits of my advice; And he, repulsed--a short tale to make-- Fell into a sadness, then into a fast, Thence to a watch, thence into a weakness, Thence to a lightness, and, by this declension, Into the madness wherein now he raves, And all we mourn for. KING CLAUDIUS Do you think 'tis this? QUEEN GERTRUDE It may be, very likely. LORD POLONIUS Hath there been such a time--I'd fain know that-- That I have positively said 'Tis so,' When it proved otherwise? KING CLAUDIUS Not that I know. LORD POLONIUS Pointing to his head and shoulder Take this from this, if this be otherwise: If circumstances lead me, I will find Where truth is hid, though it were hid indeed Within the centre. KING CLAUDIUS How may we try it further? LORD POLONIUS You know, sometimes he walks four hours together Here in the lobby. QUEEN GERTRUDE So he does indeed. LORD POLONIUS At such a time I'll loose my daughter to him: Be you and I behind an arras then; Mark the encounter: if he love her not And be not from his reason fall'n thereon, Let me be no assistant for a state, But keep a farm and carters. KING CLAUDIUS We will try it. QUEEN GERTRUDE But, look, where sadly the poor wretch comes reading. LORD POLONIUS Away, I do beseech you, both away: I'll board him presently. Exeunt KING CLAUDIUS, QUEEN GERTRUDE, and Attendants Enter HAMLET, reading O, give me leave: How does my good Lord Hamlet? HAMLET Well, God-a-mercy. LORD POLONIUS Do you know me, my lord? HAMLET Excellent well; you are a fishmonger. LORD POLONIUS Not I, my lord. HAMLET Then I would you were so honest a man. LORD POLONIUS Honest, my lord! HAMLET Ay, sir; to be honest, as this world goes, is to be one man picked out of ten thousand. LORD POLONIUS That's very true, my lord. HAMLET For if the sun breed maggots in a dead dog, being a god kissing carrion,--Have you a daughter? LORD POLONIUS I have, my lord. HAMLET Let her not walk i' the sun: conception is a blessing: but not as your daughter may conceive. Friend, look to 't. LORD POLONIUS Aside How say you by that? Still harping on my daughter: yet he knew me not at first; he said I was a fishmonger: he is far gone, far gone: and truly in my youth I suffered much extremity for love; very near this. I'll speak to him again. What do you read, my lord? HAMLET Words, words, words. LORD POLONIUS What is the matter, my lord? HAMLET Between who? LORD POLONIUS I mean, the matter that you read, my lord. HAMLET Slanders, sir: for the satirical rogue says here that old men have grey beards, that their faces are wrinkled, their eyes purging thick amber and plum-tree gum and that they have a plentiful lack of wit, together with most weak hams: all which, sir, though I most powerfully and potently believe, yet I hold it not honesty to have it thus set down, for yourself, sir, should be old as I am, if like a crab you could go backward. LORD POLONIUS Aside Though this be madness, yet there is method in 't. Will you walk out of the air, my lord? HAMLET Into my grave. LORD POLONIUS Indeed, that is out o' the air. Aside How pregnant sometimes his replies are! a happiness that often madness hits on, which reason and sanity could not so prosperously be delivered of. I will leave him, and suddenly contrive the means of meeting between him and my daughter.--My honourable lord, I will most humbly take my leave of you. HAMLET You cannot, sir, take from me any thing that I will more willingly part withal: except my life, except my life, except my life. LORD POLONIUS Fare you well, my lord. HAMLET These tedious old fools! Enter ROSENCRANTZ and GUILDENSTERN LORD POLONIUS You go to seek the Lord Hamlet; there he is. ROSENCRANTZ To POLONIUS God save you, sir! Exit POLONIUS GUILDENSTERN My honoured lord! ROSENCRANTZ My most dear lord! HAMLET My excellent good friends! How dost thou, Guildenstern? Ah, Rosencrantz! Good lads, how do ye both? ROSENCRANTZ As the indifferent children of the earth. GUILDENSTERN Happy, in that we are not over-happy; On fortune's cap we are not the very button. HAMLET Nor the soles of her shoe? ROSENCRANTZ Neither, my lord. HAMLET Then you live about her waist, or in the middle of her favours? GUILDENSTERN 'Faith, her privates we. HAMLET In the secret parts of fortune? O, most true; she is a strumpet. What's the news? ROSENCRANTZ None, my lord, but that the world's grown honest. HAMLET Then is doomsday near: but your news is not true. Let me question more in particular: what have you, my good friends, deserved at the hands of fortune, that she sends you to prison hither? GUILDENSTERN Prison, my lord! HAMLET Denmark's a prison. ROSENCRANTZ Then is the world one. HAMLET A goodly one; in which there are many confines, wards and dungeons, Denmark being one o' the worst. ROSENCRANTZ We think not so, my lord. HAMLET Why, then, 'tis none to you; for there is nothing either good or bad, but thinking makes it so: to me it is a prison. ROSENCRANTZ Why then, your ambition makes it one; 'tis too narrow for your mind. HAMLET O God, I could be bounded in a nut shell and count myself a king of infinite space, were it not that I have bad dreams. GUILDENSTERN Which dreams indeed are ambition, for the very substance of the ambitious is merely the shadow of a dream. HAMLET A dream itself is but a shadow. ROSENCRANTZ Truly, and I hold ambition of so airy and light a quality that it is but a shadow's shadow. HAMLET Then are our beggars bodies, and our monarchs and outstretched heroes the beggars' shadows. Shall we to the court? for, by my fay, I cannot reason. ROSENCRANTZ GUILDENSTERN We'll wait upon you. HAMLET No such matter: I will not sort you with the rest of my servants, for, to speak to you like an honest man, I am most dreadfully attended. But, in the beaten way of friendship, what make you at Elsinore? ROSENCRANTZ To visit you, my lord; no other occasion. HAMLET Beggar that I am, I am even poor in thanks; but I thank you: and sure, dear friends, my thanks are too dear a halfpenny. Were you not sent for? Is it your own inclining? Is it a free visitation? Come, deal justly with me: come, come; nay, speak. GUILDENSTERN What should we say, my lord? HAMLET Why, any thing, but to the purpose. You were sent for; and there is a kind of confession in your looks which your modesties have not craft enough to colour: I know the good king and queen have sent for you. ROSENCRANTZ To what end, my lord? HAMLET That you must teach me. But let me conjure you, by the rights of our fellowship, by the consonancy of our youth, by the obligation of our ever-preserved love, and by what more dear a better proposer could charge you withal, be even and direct with me, whether you were sent for, or no? ROSENCRANTZ Aside to GUILDENSTERN What say you? HAMLET Aside Nay, then, I have an eye of you.--If you love me, hold not off. GUILDENSTERN My lord, we were sent for. HAMLET I will tell you why; so shall my anticipation prevent your discovery, and your secrecy to the king and queen moult no feather. I have of late--but wherefore I know not--lost all my mirth, forgone all custom of exercises; and indeed it goes so heavily with my disposition that this goodly frame, the earth, seems to me a sterile promontory, this most excellent canopy, the air, look you, this brave o'erhanging firmament, this majestical roof fretted with golden fire, why, it appears no other thing to me than a foul and pestilent congregation of vapours. What a piece of work is a man! how noble in reason! how infinite in faculty! in form and moving how express and admirable! in action how like an angel! in apprehension how like a god! the beauty of the world! the paragon of animals! And yet, to me, what is this quintessence of dust? man delights not me: no, nor woman neither, though by your smiling you seem to say so. ROSENCRANTZ My lord, there was no such stuff in my thoughts. HAMLET Why did you laugh then, when I said 'man delights not me'? ROSENCRANTZ To think, my lord, if you delight not in man, what lenten entertainment the players shall receive from you: we coted them on the way; and hither are they coming, to offer you service. HAMLET He that plays the king shall be welcome; his majesty shall have tribute of me; the adventurous knight shall use his foil and target; the lover shall not sigh gratis; the humourous man shall end his part in peace; the clown shall make those laugh whose lungs are tickled o' the sere; and the lady shall say her mind freely, or the blank verse shall halt for't. What players are they? ROSENCRANTZ Even those you were wont to take delight in, the tragedians of the city. HAMLET How chances it they travel? their residence, both in reputation and profit, was better both ways. ROSENCRANTZ I think their inhibition comes by the means of the late innovation. HAMLET Do they hold the same estimation they did when I was in the city? are they so followed? ROSENCRANTZ No, indeed, are they not. HAMLET How comes it? do they grow rusty? ROSENCRANTZ Nay, their endeavour keeps in the wonted pace: but there is, sir, an aery of children, little eyases, that cry out on the top of question, and are most tyrannically clapped for't: these are now the fashion, and so berattle the common stages--so they call them--that many wearing rapiers are afraid of goose-quills and dare scarce come thither. HAMLET What, are they children? who maintains 'em? how are they escoted? Will they pursue the quality no longer than they can sing? will they not say afterwards, if they should grow themselves to common players--as it is most like, if their means are no better--their writers do them wrong, to make them exclaim against their own succession? ROSENCRANTZ 'Faith, there has been much to do on both sides; and the nation holds it no sin to tarre them to controversy: there was, for a while, no money bid for argument, unless the poet and the player went to cuffs in the question. HAMLET Is't possible? GUILDENSTERN O, there has been much throwing about of brains. HAMLET Do the boys carry it away? ROSENCRANTZ Ay, that they do, my lord; Hercules and his load too. HAMLET It is not very strange; for mine uncle is king of Denmark, and those that would make mows at him while my father lived, give twenty, forty, fifty, an hundred ducats a-piece for his picture in little. 'Sblood, there is something in this more than natural, if philosophy could find it out. Flourish of trumpets within GUILDENSTERN There are the players. HAMLET Gentlemen, you are welcome to Elsinore. Your hands, come then: the appurtenance of welcome is fashion and ceremony: let me comply with you in this garb, lest my extent to the players, which, I tell you, must show fairly outward, should more appear like entertainment than yours. You are welcome: but my uncle-father and aunt-mother are deceived. GUILDENSTERN In what, my dear lord? HAMLET I am but mad north-north-west: when the wind is southerly I know a hawk from a handsaw. Enter POLONIUS LORD POLONIUS Well be with you, gentlemen! HAMLET Hark you, Guildenstern; and you too: at each ear a hearer: that great baby you see there is not yet out of his swaddling-clouts. ROSENCRANTZ Happily he's the second time come to them; for they say an old man is twice a child. HAMLET I will prophesy he comes to tell me of the players; mark it. You say right, sir: o' Monday morning; 'twas so indeed. LORD POLONIUS My lord, I have news to tell you. HAMLET My lord, I have news to tell you. When Roscius was an actor in Rome,-- LORD POLONIUS The actors are come hither, my lord. HAMLET Buz, buz! LORD POLONIUS Upon mine honour,-- HAMLET Then came each actor on his ass,-- LORD POLONIUS The best actors in the world, either for tragedy, comedy, history, pastoral, pastoral-comical, historical-pastoral, tragical-historical, tragical- comical-historical-pastoral, scene individable, or poem unlimited: Seneca cannot be too heavy, nor Plautus too light. For the law of writ and the liberty, these are the only men. HAMLET O Jephthah, judge of Israel, what a treasure hadst thou! LORD POLONIUS What a treasure had he, my lord? HAMLET Why, 'One fair daughter and no more, The which he loved passing well.' LORD POLONIUS Aside Still on my daughter. HAMLET Am I not i' the right, old Jephthah? LORD POLONIUS If you call me Jephthah, my lord, I have a daughter that I love passing well. HAMLET Nay, that follows not. LORD POLONIUS What follows, then, my lord? HAMLET Why, 'As by lot, God wot,' and then, you know, 'It came to pass, as most like it was,'-- the first row of the pious chanson will show you more; for look, where my abridgement comes. Enter four or five Players You are welcome, masters; welcome, all. I am glad to see thee well. Welcome, good friends. O, my old friend! thy face is valenced since I saw thee last: comest thou to beard me in Denmark? What, my young lady and mistress! By'r lady, your ladyship is nearer to heaven than when I saw you last, by the altitude of a chopine. Pray God, your voice, like apiece of uncurrent gold, be not cracked within the ring. Masters, you are all welcome. We'll e'en to't like French falconers, fly at any thing we see: we'll have a speech straight: come, give us a taste of your quality; come, a passionate speech. First Player What speech, my lord? HAMLET I heard thee speak me a speech once, but it was never acted; or, if it was, not above once; for the play, I remember, pleased not the million; 'twas caviare to the general: but it was--as I received it, and others, whose judgments in such matters cried in the top of mine--an excellent play, well digested in the scenes, set down with as much modesty as cunning. I remember, one said there were no sallets in the lines to make the matter savoury, nor no matter in the phrase that might indict the author of affectation; but called it an honest method, as wholesome as sweet, and by very much more handsome than fine. One speech in it I chiefly loved: 'twas Aeneas' tale to Dido; and thereabout of it especially, where he speaks of Priam's slaughter: if it live in your memory, begin at this line: let me see, let me see-- 'The rugged Pyrrhus, like the Hyrcanian beast,'-- it is not so:--it begins with Pyrrhus:-- 'The rugged Pyrrhus, he whose sable arms, Black as his purpose, did the night resemble When he lay couched in the ominous horse, Hath now this dread and black complexion smear'd With heraldry more dismal; head to foot Now is he total gules; horridly trick'd With blood of fathers, mothers, daughters, sons, Baked and impasted with the parching streets, That lend a tyrannous and damned light To their lord's murder: roasted in wrath and fire, And thus o'er-sized with coagulate gore, With eyes like carbuncles, the hellish Pyrrhus Old grandsire Priam seeks.' So, proceed you. LORD POLONIUS 'Fore God, my lord, well spoken, with good accent and good discretion. First Player 'Anon he finds him Striking too short at Greeks; his antique sword, Rebellious to his arm, lies where it falls, Repugnant to command: unequal match'd, Pyrrhus at Priam drives; in rage strikes wide; But with the whiff and wind of his fell sword The unnerved father falls. Then senseless Ilium, Seeming to feel this blow, with flaming top Stoops to his base, and with a hideous crash Takes prisoner Pyrrhus' ear: for, lo! his sword, Which was declining on the milky head Of reverend Priam, seem'd i' the air to stick: So, as a painted tyrant, Pyrrhus stood, And like a neutral to his will and matter, Did nothing. But, as we often see, against some storm, A silence in the heavens, the rack stand still, The bold winds speechless and the orb below As hush as death, anon the dreadful thunder Doth rend the region, so, after Pyrrhus' pause, Aroused vengeance sets him new a-work; And never did the Cyclops' hammers fall On Mars's armour forged for proof eterne With less remorse than Pyrrhus' bleeding sword Now falls on Priam. Out, out, thou strumpet, Fortune! All you gods, In general synod 'take away her power; Break all the spokes and fellies from her wheel, And bowl the round nave down the hill of heaven, As low as to the fiends!' LORD POLONIUS This is too long. HAMLET It shall to the barber's, with your beard. Prithee, say on: he's for a jig or a tale of bawdry, or he sleeps: say on: come to Hecuba. First Player 'But who, O, who had seen the mobled queen--' HAMLET 'The mobled queen?' LORD POLONIUS That's good; 'mobled queen' is good. First Player 'Run barefoot up and down, threatening the flames With bisson rheum; a clout upon that head Where late the diadem stood, and for a robe, About her lank and all o'er-teemed loins, A blanket, in the alarm of fear caught up; Who this had seen, with tongue in venom steep'd, 'Gainst Fortune's state would treason have pronounced: But if the gods themselves did see her then When she saw Pyrrhus make malicious sport In mincing with his sword her husband's limbs, The instant burst of clamour that she made, Unless things mortal move them not at all, Would have made milch the burning eyes of heaven, And passion in the gods.' LORD POLONIUS Look, whether he has not turned his colour and has tears in's eyes. Pray you, no more. HAMLET 'Tis well: I'll have thee speak out the rest soon. Good my lord, will you see the players well bestowed? Do you hear, let them be well used; for they are the abstract and brief chronicles of the time: after your death you were better have a bad epitaph than their ill report while you live. LORD POLONIUS My lord, I will use them according to their desert. HAMLET God's bodykins, man, much better: use every man after his desert, and who should 'scape whipping? Use them after your own honour and dignity: the less they deserve, the more merit is in your bounty. Take them in. LORD POLONIUS Come, sirs. HAMLET Follow him, friends: we'll hear a play to-morrow. Exit POLONIUS with all the Players but the First Dost thou hear me, old friend; can you play the Murder of Gonzago? First Player Ay, my lord. HAMLET We'll ha't to-morrow night. You could, for a need, study a speech of some dozen or sixteen lines, which I would set down and insert in't, could you not? First Player Ay, my lord. HAMLET Very well. Follow that lord; and look you mock him not. Exit First Player My good friends, I'll leave you till night: you are welcome to Elsinore. ROSENCRANTZ Good my lord! HAMLET Ay, so, God be wi' ye; Exeunt ROSENCRANTZ and GUILDENSTERN Now I am alone. O, what a rogue and peasant slave am I! Is it not monstrous that this player here, But in a fiction, in a dream of passion, Could force his soul so to his own conceit That from her working all his visage wann'd, Tears in his eyes, distraction in's aspect, A broken voice, and his whole function suiting With forms to his conceit? and all for nothing! For Hecuba! What's Hecuba to him, or he to Hecuba, That he should weep for her? What would he do, Had he the motive and the cue for passion That I have? He would drown the stage with tears And cleave the general ear with horrid speech, Make mad the guilty and appal the free, Confound the ignorant, and amaze indeed The very faculties of eyes and ears. Yet I, A dull and muddy-mettled rascal, peak, Like John-a-dreams, unpregnant of my cause, And can say nothing; no, not for a king, Upon whose property and most dear life A damn'd defeat was made. Am I a coward? Who calls me villain? breaks my pate across? Plucks off my beard, and blows it in my face? Tweaks me by the nose? gives me the lie i' the throat, As deep as to the lungs? who does me this? Ha! 'Swounds, I should take it: for it cannot be But I am pigeon-liver'd and lack gall To make oppression bitter, or ere this I should have fatted all the region kites With this slave's offal: bloody, bawdy villain! Remorseless, treacherous, lecherous, kindless villain! O, vengeance! Why, what an ass am I! This is most brave, That I, the son of a dear father murder'd, Prompted to my revenge by heaven and hell, Must, like a whore, unpack my heart with words, And fall a-cursing, like a very drab, A scullion! Fie upon't! foh! About, my brain! I have heard That guilty creatures sitting at a play Have by the very cunning of the scene Been struck so to the soul that presently They have proclaim'd their malefactions; For murder, though it have no tongue, will speak With most miraculous organ. I'll have these players Play something like the murder of my father Before mine uncle: I'll observe his looks; I'll tent him to the quick: if he but blench, I know my course. The spirit that I have seen May be the devil: and the devil hath power To assume a pleasing shape; yea, and perhaps Out of my weakness and my melancholy, As he is very potent with such spirits, Abuses me to damn me: I'll have grounds More relative than this: the play 's the thing Wherein I'll catch the conscience of the king. Exit ACT III SCENE I. A room in the castle. Enter KING CLAUDIUS, QUEEN GERTRUDE, POLONIUS, OPHELIA, ROSENCRANTZ, and GUILDENSTERN KING CLAUDIUS And can you, by no drift of circumstance, Get from him why he puts on this confusion, Grating so harshly all his days of quiet With turbulent and dangerous lunacy? ROSENCRANTZ He does confess he feels himself distracted; But from what cause he will by no means speak. GUILDENSTERN Nor do we find him forward to be sounded, But, with a crafty madness, keeps aloof, When we would bring him on to some confession Of his true state. QUEEN GERTRUDE Did he receive you well? ROSENCRANTZ Most like a gentleman. GUILDENSTERN But with much forcing of his disposition. ROSENCRANTZ Niggard of question; but, of our demands, Most free in his reply. QUEEN GERTRUDE Did you assay him? To any pastime? ROSENCRANTZ Madam, it so fell out, that certain players We o'er-raught on the way: of these we told him; And there did seem in him a kind of joy To hear of it: they are about the court, And, as I think, they have already order This night to play before him. LORD POLONIUS 'Tis most true: And he beseech'd me to entreat your majesties To hear and see the matter. KING CLAUDIUS With all my heart; and it doth much content me To hear him so inclined. Good gentlemen, give him a further edge, And drive his purpose on to these delights. ROSENCRANTZ We shall, my lord. Exeunt ROSENCRANTZ and GUILDENSTERN KING CLAUDIUS Sweet Gertrude, leave us too; For we have closely sent for Hamlet hither, That he, as 'twere by accident, may here Affront Ophelia: Her father and myself, lawful espials, Will so bestow ourselves that, seeing, unseen, We may of their encounter frankly judge, And gather by him, as he is behaved, If 't be the affliction of his love or no That thus he suffers for. QUEEN GERTRUDE I shall obey you. And for your part, Ophelia, I do wish That your good beauties be the happy cause Of Hamlet's wildness: so shall I hope your virtues Will bring him to his wonted way again, To both your honours. OPHELIA Madam, I wish it may. Exit QUEEN GERTRUDE LORD POLONIUS Ophelia, walk you here. Gracious, so please you, We will bestow ourselves. To OPHELIA Read on this book; That show of such an exercise may colour Your loneliness. We are oft to blame in this,-- 'Tis too much proved--that with devotion's visage And pious action we do sugar o'er The devil himself. KING CLAUDIUS Aside O, 'tis too true! How smart a lash that speech doth give my conscience! The harlot's cheek, beautied with plastering art, Is not more ugly to the thing that helps it Than is my deed to my most painted word: O heavy burthen! LORD POLONIUS I hear him coming: let's withdraw, my lord. Exeunt KING CLAUDIUS and POLONIUS Enter HAMLET HAMLET To be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take arms against a sea of troubles, And by opposing end them? To die: to sleep; No more; and by a sleep to say we end The heart-ache and the thousand natural shocks That flesh is heir to, 'tis a consummation Devoutly to be wish'd. To die, to sleep; To sleep: perchance to dream: ay, there's the rub; For in that sleep of death what dreams may come When we have shuffled off this mortal coil, Must give us pause: there's the respect That makes calamity of so long life; For who would bear the whips and scorns of time, The oppressor's wrong, the proud man's contumely, The pangs of despised love, the law's delay, The insolence of office and the spurns That patient merit of the unworthy takes, When he himself might his quietus make With a bare bodkin? who would fardels bear, To grunt and sweat under a weary life, But that the dread of something after death, The undiscover'd country from whose bourn No traveller returns, puzzles the will And makes us rather bear those ills we have Than fly to others that we know not of? Thus conscience does make cowards of us all; And thus the native hue of resolution Is sicklied o'er with the pale cast of thought, And enterprises of great pith and moment With this regard their currents turn awry, And lose the name of action.--Soft you now! The fair Ophelia! Nymph, in thy orisons Be all my sins remember'd. OPHELIA Good my lord, How does your honour for this many a day? HAMLET I humbly thank you; well, well, well. OPHELIA My lord, I have remembrances of yours, That I have longed long to re-deliver; I pray you, now receive them. HAMLET No, not I; I never gave you aught. OPHELIA My honour'd lord, you know right well you did; And, with them, words of so sweet breath composed As made the things more rich: their perfume lost, Take these again; for to the noble mind Rich gifts wax poor when givers prove unkind. There, my lord. HAMLET Ha, ha! are you honest? OPHELIA My lord? HAMLET Are you fair? OPHELIA What means your lordship? HAMLET That if you be honest and fair, your honesty should admit no discourse to your beauty. OPHELIA Could beauty, my lord, have better commerce than with honesty? HAMLET Ay, truly; for the power of beauty will sooner transform honesty from what it is to a bawd than the force of honesty can translate beauty into his likeness: this was sometime a paradox, but now the time gives it proof. I did love you once. OPHELIA Indeed, my lord, you made me believe so. HAMLET You should not have believed me; for virtue cannot so inoculate our old stock but we shall relish of it: I loved you not. OPHELIA I was the more deceived. HAMLET Get thee to a nunnery: why wouldst thou be a breeder of sinners? I am myself indifferent honest; but yet I could accuse me of such things that it were better my mother had not borne me: I am very proud, revengeful, ambitious, with more offences at my beck than I have thoughts to put them in, imagination to give them shape, or time to act them in. What should such fellows as I do crawling between earth and heaven? We are arrant knaves, all; believe none of us. Go thy ways to a nunnery. Where's your father? OPHELIA At home, my lord. HAMLET Let the doors be shut upon him, that he may play the fool no where but in's own house. Farewell. OPHELIA O, help him, you sweet heavens! HAMLET If thou dost marry, I'll give thee this plague for thy dowry: be thou as chaste as ice, as pure as snow, thou shalt not escape calumny. Get thee to a nunnery, go: farewell. Or, if thou wilt needs marry, marry a fool; for wise men know well enough what monsters you make of them. To a nunnery, go, and quickly too. Farewell. OPHELIA O heavenly powers, restore him! HAMLET I have heard of your paintings too, well enough; God has given you one face, and you make yourselves another: you jig, you amble, and you lisp, and nick-name God's creatures, and make your wantonness your ignorance. Go to, I'll no more on't; it hath made me mad. I say, we will have no more marriages: those that are married already, all but one, shall live; the rest shall keep as they are. To a nunnery, go. Exit OPHELIA O, what a noble mind is here o'erthrown! The courtier's, soldier's, scholar's, eye, tongue, sword; The expectancy and rose of the fair state, The glass of fashion and the mould of form, The observed of all observers, quite, quite down! And I, of ladies most deject and wretched, That suck'd the honey of his music vows, Now see that noble and most sovereign reason, Like sweet bells jangled, out of tune and harsh; That unmatch'd form and feature of blown youth Blasted with ecstasy: O, woe is me, To have seen what I have seen, see what I see! Re-enter KING CLAUDIUS and POLONIUS KING CLAUDIUS Love! his affections do not that way tend; Nor what he spake, though it lack'd form a little, Was not like madness. There's something in his soul, O'er which his melancholy sits on brood; And I do doubt the hatch and the disclose Will be some danger: which for to prevent, I have in quick determination Thus set it down: he shall with speed to England, For the demand of our neglected tribute Haply the seas and countries different With variable objects shall expel This something-settled matter in his heart, Whereon his brains still beating puts him thus From fashion of himself. What think you on't? LORD POLONIUS It shall do well: but yet do I believe The origin and commencement of his grief Sprung from neglected love. How now, Ophelia! You need not tell us what Lord Hamlet said; We heard it all. My lord, do as you please; But, if you hold it fit, after the play Let his queen mother all alone entreat him To show his grief: let her be round with him; And I'll be placed, so please you, in the ear Of all their conference. If she find him not, To England send him, or confine him where Your wisdom best shall think. KING CLAUDIUS It shall be so: Madness in great ones must not unwatch'd go. Exeunt SCENE II. A hall in the castle. Enter HAMLET and Players HAMLET Speak the speech, I pray you, as I pronounced it to you, trippingly on the tongue: but if you mouth it, as many of your players do, I had as lief the town-crier spoke my lines. Nor do not saw the air too much with your hand, thus, but use all gently; for in the very torrent, tempest, and, as I may say, the whirlwind of passion, you must acquire and beget a temperance that may give it smoothness. O, it offends me to the soul to hear a robustious periwig-pated fellow tear a passion to tatters, to very rags, to split the ears of the groundlings, who for the most part are capable of nothing but inexplicable dumbshows and noise: I would have such a fellow whipped for o'erdoing Termagant; it out-herods Herod: pray you, avoid it. First Player I warrant your honour. HAMLET Be not too tame neither, but let your own discretion be your tutor: suit the action to the word, the word to the action; with this special o'erstep not the modesty of nature: for any thing so overdone is from the purpose of playing, whose end, both at the first and now, was and is, to hold, as 'twere, the mirror up to nature; to show virtue her own feature, scorn her own image, and the very age and body of the time his form and pressure. Now this overdone, or come tardy off, though it make the unskilful laugh, cannot but make the judicious grieve; the censure of the which one must in your allowance o'erweigh a whole theatre of others. O, there be players that I have seen play, and heard others praise, and that highly, not to speak it profanely, that, neither having the accent of Christians nor the gait of Christian, pagan, nor man, have so strutted and bellowed that I have thought some of nature's journeymen had made men and not made them well, they imitated humanity so abominably. First Player I hope we have reformed that indifferently with us, sir. HAMLET O, reform it altogether. And let those that play your clowns speak no more than is set down for them; for there be of them that will themselves laugh, to set on some quantity of barren spectators to laugh too; though, in the mean time, some necessary question of the play be then to be considered: that's villanous, and shows a most pitiful ambition in the fool that uses it. Go, make you ready. Exeunt Players Enter POLONIUS, ROSENCRANTZ, and GUILDENSTERN How now, my lord! I will the king hear this piece of work? LORD POLONIUS And the queen too, and that presently. HAMLET Bid the players make haste. Exit POLONIUS Will you two help to hasten them? ROSENCRANTZ GUILDENSTERN We will, my lord. Exeunt ROSENCRANTZ and GUILDENSTERN HAMLET What ho! Horatio! Enter HORATIO HORATIO Here, sweet lord, at your service. HAMLET Horatio, thou art e'en as just a man As e'er my conversation coped withal. HORATIO O, my dear lord,-- HAMLET Nay, do not think I flatter; For what advancement may I hope from thee That no revenue hast but thy good spirits, To feed and clothe thee? Why should the poor be flatter'd? No, let the candied tongue lick absurd pomp, And crook the pregnant hinges of the knee Where thrift may follow fawning. Dost thou hear? Since my dear soul was mistress of her choice And could of men distinguish, her election Hath seal'd thee for herself; for thou hast been As one, in suffering all, that suffers nothing, A man that fortune's buffets and rewards Hast ta'en with equal thanks: and blest are those Whose blood and judgment are so well commingled, That they are not a pipe for fortune's finger To sound what stop she please. Give me that man That is not passion's slave, and I will wear him In my heart's core, ay, in my heart of heart, As I do thee.--Something too much of this.-- There is a play to-night before the king; One scene of it comes near the circumstance Which I have told thee of my father's death: I prithee, when thou seest that act afoot, Even with the very comment of thy soul Observe mine uncle: if his occulted guilt Do not itself unkennel in one speech, It is a damned ghost that we have seen, And my imaginations are as foul As Vulcan's stithy. Give him heedful note; For I mine eyes will rivet to his face, And after we will both our judgments join In censure of his seeming. HORATIO Well, my lord: If he steal aught the whilst this play is playing, And 'scape detecting, I will pay the theft. HAMLET They are coming to the play; I must be idle: Get you a place. Danish march. A flourish. Enter KING CLAUDIUS, QUEEN GERTRUDE, POLONIUS, OPHELIA, ROSENCRANTZ, GUILDENSTERN, and others KING CLAUDIUS How fares our cousin Hamlet? HAMLET Excellent, i' faith; of the chameleon's dish: I eat the air, promise-crammed: you cannot feed capons so. KING CLAUDIUS I have nothing with this answer, Hamlet; these words are not mine. HAMLET No, nor mine now. To POLONIUS My lord, you played once i' the university, you say? LORD POLONIUS That did I, my lord; and was accounted a good actor. HAMLET What did you enact? LORD POLONIUS I did enact Julius Caesar: I was killed i' the Capitol; Brutus killed me. HAMLET It was a brute part of him to kill so capital a calf there. Be the players ready? ROSENCRANTZ Ay, my lord; they stay upon your patience. QUEEN GERTRUDE Come hither, my dear Hamlet, sit by me. HAMLET No, good mother, here's metal more attractive. LORD POLONIUS To KING CLAUDIUS O, ho! do you mark that? HAMLET Lady, shall I lie in your lap? Lying down at OPHELIA's feet OPHELIA No, my lord. HAMLET I mean, my head upon your lap? OPHELIA Ay, my lord. HAMLET Do you think I meant country matters? OPHELIA I think nothing, my lord. HAMLET That's a fair thought to lie between maids' legs. OPHELIA What is, my lord? HAMLET Nothing. OPHELIA You are merry, my lord. HAMLET Who, I? OPHELIA Ay, my lord. HAMLET O God, your only jig-maker. What should a man do but be merry? for, look you, how cheerfully my mother looks, and my father died within these two hours. OPHELIA Nay, 'tis twice two months, my lord. HAMLET So long? Nay then, let the devil wear black, for I'll have a suit of sables. O heavens! die two months ago, and not forgotten yet? Then there's hope a great man's memory may outlive his life half a year: but, by'r lady, he must build churches, then; or else shall he suffer not thinking on, with the hobby-horse, whose epitaph is 'For, O, for, O, the hobby-horse is forgot.' Hautboys play. The dumb-show enters Enter a King and a Queen very lovingly; the Queen embracing him, and he her. She kneels, and makes show of protestation unto him. He takes her up, and declines his head upon her neck: lays him down upon a bank of flowers: she, seeing him asleep, leaves him. Anon comes in a fellow, takes off his crown, kisses it, and pours poison in the King's ears, and exit. The Queen returns; finds the King dead, and makes passionate action. The Poisoner, with some two or three Mutes, comes in again, seeming to lament with her. The dead body is carried away. The Poisoner wooes the Queen with gifts: she seems loath and unwilling awhile, but in the end accepts his love Exeunt OPHELIA What means this, my lord? HAMLET Marry, this is miching mallecho; it means mischief. OPHELIA Belike this show imports the argument of the play. Enter Prologue HAMLET We shall know by this fellow: the players cannot keep counsel; they'll tell all. OPHELIA Will he tell us what this show meant? HAMLET Ay, or any show that you'll show him: be not you ashamed to show, he'll not shame to tell you what it means. OPHELIA You are naught, you are naught: I'll mark the play. Prologue For us, and for our tragedy, Here stooping to your clemency, We beg your hearing patiently. Exit HAMLET Is this a prologue, or the posy of a ring? OPHELIA 'Tis brief, my lord. HAMLET As woman's love. Enter two Players, King and Queen Player King Full thirty times hath Phoebus' cart gone round Neptune's salt wash and Tellus' orbed ground, And thirty dozen moons with borrow'd sheen About the world have times twelve thirties been, Since love our hearts and Hymen did our hands Unite commutual in most sacred bands. Player Queen So many journeys may the sun and moon Make us again count o'er ere love be done! But, woe is me, you are so sick of late, So far from cheer and from your former state, That I distrust you. Yet, though I distrust, Discomfort you, my lord, it nothing must: For women's fear and love holds quantity; In neither aught, or in extremity. Now, what my love is, proof hath made you know; And as my love is sized, my fear is so: Where love is great, the littlest doubts are fear; Where little fears grow great, great love grows there. Player King 'Faith, I must leave thee, love, and shortly too; My operant powers their functions leave to do: And thou shalt live in this fair world behind, Honour'd, beloved; and haply one as kind For husband shalt thou-- Player Queen O, confound the rest! Such love must needs be treason in my breast: In second husband let me be accurst! None wed the second but who kill'd the first. HAMLET Aside Wormwood, wormwood. Player Queen The instances that second marriage move Are base respects of thrift, but none of love: A second time I kill my husband dead, When second husband kisses me in bed. Player King I do believe you think what now you speak; But what we do determine oft we break. Purpose is but the slave to memory, Of violent birth, but poor validity; Which now, like fruit unripe, sticks on the tree; But fall, unshaken, when they mellow be. Most necessary 'tis that we forget To pay ourselves what to ourselves is debt: What to ourselves in passion we propose, The passion ending, doth the purpose lose. The violence of either grief or joy Their own enactures with themselves destroy: Where joy most revels, grief doth most lament; Grief joys, joy grieves, on slender accident. This world is not for aye, nor 'tis not strange That even our loves should with our fortunes change; For 'tis a question left us yet to prove, Whether love lead fortune, or else fortune love. The great man down, you mark his favourite flies; The poor advanced makes friends of enemies. And hitherto doth love on fortune tend; For who not needs shall never lack a friend, And who in want a hollow friend doth try, Directly seasons him his enemy. But, orderly to end where I begun, Our wills and fates do so contrary run That our devices still are overthrown; Our thoughts are ours, their ends none of our own: So think thou wilt no second husband wed; But die thy thoughts when thy first lord is dead. Player Queen Nor earth to me give food, nor heaven light! Sport and repose lock from me day and night! To desperation turn my trust and hope! An anchor's cheer in prison be my scope! Each opposite that blanks the face of joy Meet what I would have well and it destroy! Both here and hence pursue me lasting strife, If, once a widow, ever I be wife! HAMLET If she should break it now! Player King 'Tis deeply sworn. Sweet, leave me here awhile; My spirits grow dull, and fain I would beguile The tedious day with sleep. Sleeps Player Queen Sleep rock thy brain, And never come mischance between us twain! Exit HAMLET Madam, how like you this play? QUEEN GERTRUDE The lady protests too much, methinks. HAMLET O, but she'll keep her word. KING CLAUDIUS Have you heard the argument? Is there no offence in 't? HAMLET No, no, they do but jest, poison in jest; no offence i' the world. KING CLAUDIUS What do you call the play? HAMLET The Mouse-trap. Marry, how? Tropically. This play is the image of a murder done in Vienna: Gonzago is the duke's name; his wife, Baptista: you shall see anon; 'tis a knavish piece of work: but what o' that? your majesty and we that have free souls, it touches us not: let the galled jade wince, our withers are unwrung. Enter LUCIANUS This is one Lucianus, nephew to the king. OPHELIA You are as good as a chorus, my lord. HAMLET I could interpret between you and your love, if I could see the puppets dallying. OPHELIA You are keen, my lord, you are keen. HAMLET It would cost you a groaning to take off my edge. OPHELIA Still better, and worse. HAMLET So you must take your husbands. Begin, murderer; pox, leave thy damnable faces, and begin. Come: 'the croaking raven doth bellow for revenge.' LUCIANUS Thoughts black, hands apt, drugs fit, and time agreeing; Confederate season, else no creature seeing; Thou mixture rank, of midnight weeds collected, With Hecate's ban thrice blasted, thrice infected, Thy natural magic and dire property, On wholesome life usurp immediately. Pours the poison into the sleeper's ears HAMLET He poisons him i' the garden for's estate. His name's Gonzago: the story is extant, and writ in choice Italian: you shall see anon how the murderer gets the love of Gonzago's wife. OPHELIA The king rises. HAMLET What, frighted with false fire! QUEEN GERTRUDE How fares my lord? LORD POLONIUS Give o'er the play. KING CLAUDIUS Give me some light: away! All Lights, lights, lights! Exeunt all but HAMLET and HORATIO HAMLET Why, let the stricken deer go weep, The hart ungalled play; For some must watch, while some must sleep: So runs the world away. Would not this, sir, and a forest of feathers-- if the rest of my fortunes turn Turk with me--with two Provincial roses on my razed shoes, get me a fellowship in a cry of players, sir? HORATIO Half a share. HAMLET A whole one, I. For thou dost know, O Damon dear, This realm dismantled was Of Jove himself; and now reigns here A very, very--pajock. HORATIO You might have rhymed. HAMLET O good Horatio, I'll take the ghost's word for a thousand pound. Didst perceive? HORATIO Very well, my lord. HAMLET Upon the talk of the poisoning? HORATIO I did very well note him. HAMLET Ah, ha! Come, some music! come, the recorders! For if the king like not the comedy, Why then, belike, he likes it not, perdy. Come, some music! Re-enter ROSENCRANTZ and GUILDENSTERN GUILDENSTERN Good my lord, vouchsafe me a word with you. HAMLET Sir, a whole history. GUILDENSTERN The king, sir,-- HAMLET Ay, sir, what of him? GUILDENSTERN Is in his retirement marvellous distempered. HAMLET With drink, sir? GUILDENSTERN No, my lord, rather with choler. HAMLET Your wisdom should show itself more richer to signify this to his doctor; for, for me to put him to his purgation would perhaps plunge him into far more choler. GUILDENSTERN Good my lord, put your discourse into some frame and start not so wildly from my affair. HAMLET I am tame, sir: pronounce. GUILDENSTERN The queen, your mother, in most great affliction of spirit, hath sent me to you. HAMLET You are welcome. GUILDENSTERN Nay, good my lord, this courtesy is not of the right breed. If it shall please you to make me a wholesome answer, I will do your mother's commandment: if not, your pardon and my return shall be the end of my business. HAMLET Sir, I cannot. GUILDENSTERN What, my lord? HAMLET Make you a wholesome answer; my wit's diseased: but, sir, such answer as I can make, you shall command; or, rather, as you say, my mother: therefore no more, but to the matter: my mother, you say,-- ROSENCRANTZ Then thus she says; your behavior hath struck her into amazement and admiration. HAMLET O wonderful son, that can so astonish a mother! But is there no sequel at the heels of this mother's admiration? Impart. ROSENCRANTZ She desires to speak with you in her closet, ere you go to bed. HAMLET We shall obey, were she ten times our mother. Have you any further trade with us? ROSENCRANTZ My lord, you once did love me. HAMLET So I do still, by these pickers and stealers. ROSENCRANTZ Good my lord, what is your cause of distemper? you do, surely, bar the door upon your own liberty, if you deny your griefs to your friend. HAMLET Sir, I lack advancement. ROSENCRANTZ How can that be, when you have the voice of the king himself for your succession in Denmark? HAMLET Ay, but sir, 'While the grass grows,'--the proverb is something musty. Re-enter Players with recorders O, the recorders! let me see one. To withdraw with you:--why do you go about to recover the wind of me, as if you would drive me into a toil? GUILDENSTERN O, my lord, if my duty be too bold, my love is too unmannerly. HAMLET I do not well understand that. Will you play upon this pipe? GUILDENSTERN My lord, I cannot. HAMLET I pray you. GUILDENSTERN Believe me, I cannot. HAMLET I do beseech you. GUILDENSTERN I know no touch of it, my lord. HAMLET 'Tis as easy as lying: govern these ventages with your lingers and thumb, give it breath with your mouth, and it will discourse most eloquent music. Look you, these are the stops. GUILDENSTERN But these cannot I command to any utterance of harmony; I have not the skill. HAMLET Why, look you now, how unworthy a thing you make of me! You would play upon me; you would seem to know my stops; you would pluck out the heart of my mystery; you would sound me from my lowest note to the top of my compass: and there is much music, excellent voice, in this little organ; yet cannot you make it speak. 'Sblood, do you think I am easier to be played on than a pipe? Call me what instrument you will, though you can fret me, yet you cannot play upon me. Enter POLONIUS God bless you, sir! LORD POLONIUS My lord, the queen would speak with you, and presently. HAMLET Do you see yonder cloud that's almost in shape of a camel? LORD POLONIUS By the mass, and 'tis like a camel, indeed. HAMLET Methinks it is like a weasel. LORD POLONIUS It is backed like a weasel. HAMLET Or like a whale? LORD POLONIUS Very like a whale. HAMLET Then I will come to my mother by and by. They fool me to the top of my bent. I will come by and by. LORD POLONIUS I will say so. HAMLET By and by is easily said. Exit POLONIUS Leave me, friends. Exeunt all but HAMLET Tis now the very witching time of night, When churchyards yawn and hell itself breathes out Contagion to this world: now could I drink hot blood, And do such bitter business as the day Would quake to look on. Soft! now to my mother. O heart, lose not thy nature; let not ever The soul of Nero enter this firm bosom: Let me be cruel, not unnatural: I will speak daggers to her, but use none; My tongue and soul in this be hypocrites; How in my words soever she be shent, To give them seals never, my soul, consent! Exit SCENE III. A room in the castle. Enter KING CLAUDIUS, ROSENCRANTZ, and GUILDENSTERN KING CLAUDIUS I like him not, nor stands it safe with us To let his madness range. Therefore prepare you; I your commission will forthwith dispatch, And he to England shall along with you: The terms of our estate may not endure Hazard so dangerous as doth hourly grow Out of his lunacies. GUILDENSTERN We will ourselves provide: Most holy and religious fear it is To keep those many many bodies safe That live and feed upon your majesty. ROSENCRANTZ The single and peculiar life is bound, With all the strength and armour of the mind, To keep itself from noyance; but much more That spirit upon whose weal depend and rest The lives of many. The cease of majesty Dies not alone; but, like a gulf, doth draw What's near it with it: it is a massy wheel, Fix'd on the summit of the highest mount, To whose huge spokes ten thousand lesser things Are mortised and adjoin'd; which, when it falls, Each small annexment, petty consequence, Attends the boisterous ruin. Never alone Did the king sigh, but with a general groan. KING CLAUDIUS Arm you, I pray you, to this speedy voyage; For we will fetters put upon this fear, Which now goes too free-footed. ROSENCRANTZ GUILDENSTERN We will haste us. Exeunt ROSENCRANTZ and GUILDENSTERN Enter POLONIUS LORD POLONIUS My lord, he's going to his mother's closet: Behind the arras I'll convey myself, To hear the process; and warrant she'll tax him home: And, as you said, and wisely was it said, 'Tis meet that some more audience than a mother, Since nature makes them partial, should o'erhear The speech, of vantage. Fare you well, my liege: I'll call upon you ere you go to bed, And tell you what I know. KING CLAUDIUS Thanks, dear my lord. Exit POLONIUS O, my offence is rank it smells to heaven; It hath the primal eldest curse upon't, A brother's murder. Pray can I not, Though inclination be as sharp as will: My stronger guilt defeats my strong intent; And, like a man to double business bound, I stand in pause where I shall first begin, And both neglect. What if this cursed hand Were thicker than itself with brother's blood, Is there not rain enough in the sweet heavens To wash it white as snow? Whereto serves mercy But to confront the visage of offence? And what's in prayer but this two-fold force, To be forestalled ere we come to fall, Or pardon'd being down? Then I'll look up; My fault is past. But, O, what form of prayer Can serve my turn? 'Forgive me my foul murder'? That cannot be; since I am still possess'd Of those effects for which I did the murder, My crown, mine own ambition and my queen. May one be pardon'd and retain the offence? In the corrupted currents of this world Offence's gilded hand may shove by justice, And oft 'tis seen the wicked prize itself Buys out the law: but 'tis not so above; There is no shuffling, there the action lies In his true nature; and we ourselves compell'd, Even to the teeth and forehead of our faults, To give in evidence. What then? what rests? Try what repentance can: what can it not? Yet what can it when one can not repent? O wretched state! O bosom black as death! O limed soul, that, struggling to be free, Art more engaged! Help, angels! Make assay! Bow, stubborn knees; and, heart with strings of steel, Be soft as sinews of the newborn babe! All may be well. Retires and kneels Enter HAMLET HAMLET Now might I do it pat, now he is praying; And now I'll do't. And so he goes to heaven; And so am I revenged. That would be scann'd: A villain kills my father; and for that, I, his sole son, do this same villain send To heaven. O, this is hire and salary, not revenge. He took my father grossly, full of bread; With all his crimes broad blown, as flush as May; And how his audit stands who knows save heaven? But in our circumstance and course of thought, 'Tis heavy with him: and am I then revenged, To take him in the purging of his soul, When he is fit and season'd for his passage? No! Up, sword; and know thou a more horrid hent: When he is drunk asleep, or in his rage, Or in the incestuous pleasure of his bed; At gaming, swearing, or about some act That has no relish of salvation in't; Then trip him, that his heels may kick at heaven, And that his soul may be as damn'd and black As hell, whereto it goes. My mother stays: This physic but prolongs thy sickly days. Exit KING CLAUDIUS Rising My words fly up, my thoughts remain below: Words without thoughts never to heaven go. Exit SCENE IV. The Queen's closet. Enter QUEEN MARGARET and POLONIUS LORD POLONIUS He will come straight. Look you lay home to him: Tell him his pranks have been too broad to bear with, And that your grace hath screen'd and stood between Much heat and him. I'll sconce me even here. Pray you, be round with him. HAMLET Within Mother, mother, mother! QUEEN GERTRUDE I'll warrant you, Fear me not: withdraw, I hear him coming. POLONIUS hides behind the arras Enter HAMLET HAMLET Now, mother, what's the matter? QUEEN GERTRUDE Hamlet, thou hast thy father much offended. HAMLET Mother, you have my father much offended. QUEEN GERTRUDE Come, come, you answer with an idle tongue. HAMLET Go, go, you question with a wicked tongue. QUEEN GERTRUDE Why, how now, Hamlet! HAMLET What's the matter now? QUEEN GERTRUDE Have you forgot me? HAMLET No, by the rood, not so: You are the queen, your husband's brother's wife; And--would it were not so!--you are my mother. QUEEN GERTRUDE Nay, then, I'll set those to you that can speak. HAMLET Come, come, and sit you down; you shall not budge; You go not till I set you up a glass Where you may see the inmost part of you. QUEEN GERTRUDE What wilt thou do? thou wilt not murder me? Help, help, ho! LORD POLONIUS Behind What, ho! help, help, help! HAMLET Drawing How now! a rat? Dead, for a ducat, dead! Makes a pass through the arras LORD POLONIUS Behind O, I am slain! Falls and dies QUEEN GERTRUDE O me, what hast thou done? HAMLET Nay, I know not: Is it the king? QUEEN GERTRUDE O, what a rash and bloody deed is this! HAMLET A bloody deed! almost as bad, good mother, As kill a king, and marry with his brother. QUEEN GERTRUDE As kill a king! HAMLET Ay, lady, 'twas my word. Lifts up the array and discovers POLONIUS Thou wretched, rash, intruding fool, farewell! I took thee for thy better: take thy fortune; Thou find'st to be too busy is some danger. Leave wringing of your hands: peace! sit you down, And let me wring your heart; for so I shall, If it be made of penetrable stuff, If damned custom have not brass'd it so That it is proof and bulwark against sense. QUEEN GERTRUDE What have I done, that thou darest wag thy tongue In noise so rude against me? HAMLET Such an act That blurs the grace and blush of modesty, Calls virtue hypocrite, takes off the rose From the fair forehead of an innocent love And sets a blister there, makes marriage-vows As false as dicers' oaths: O, such a deed As from the body of contraction plucks The very soul, and sweet religion makes A rhapsody of words: heaven's face doth glow: Yea, this solidity and compound mass, With tristful visage, as against the doom, Is thought-sick at the act. QUEEN GERTRUDE Ay me, what act, That roars so loud, and thunders in the index? HAMLET Look here, upon this picture, and on this, The counterfeit presentment of two brothers. See, what a grace was seated on this brow; Hyperion's curls; the front of Jove himself; An eye like Mars, to threaten and command; A station like the herald Mercury New-lighted on a heaven-kissing hill; A combination and a form indeed, Where every god did seem to set his seal, To give the world assurance of a man: This was your husband. Look you now, what follows: Here is your husband; like a mildew'd ear, Blasting his wholesome brother. Have you eyes? Could you on this fair mountain leave to feed, And batten on this moor? Ha! have you eyes? You cannot call it love; for at your age The hey-day in the blood is tame, it's humble, And waits upon the judgment: and what judgment Would step from this to this? Sense, sure, you have, Else could you not have motion; but sure, that sense Is apoplex'd; for madness would not err, Nor sense to ecstasy was ne'er so thrall'd But it reserved some quantity of choice, To serve in such a difference. What devil was't That thus hath cozen'd you at hoodman-blind? Eyes without feeling, feeling without sight, Ears without hands or eyes, smelling sans all, Or but a sickly part of one true sense Could not so mope. O shame! where is thy blush? Rebellious hell, If thou canst mutine in a matron's bones, To flaming youth let virtue be as wax, And melt in her own fire: proclaim no shame When the compulsive ardour gives the charge, Since frost itself as actively doth burn And reason panders will. QUEEN GERTRUDE O Hamlet, speak no more: Thou turn'st mine eyes into my very soul; And there I see such black and grained spots As will not leave their tinct. HAMLET Nay, but to live In the rank sweat of an enseamed bed, Stew'd in corruption, honeying and making love Over the nasty sty,-- QUEEN GERTRUDE O, speak to me no more; These words, like daggers, enter in mine ears; No more, sweet Hamlet! HAMLET A murderer and a villain; A slave that is not twentieth part the tithe Of your precedent lord; a vice of kings; A cutpurse of the empire and the rule, That from a shelf the precious diadem stole, And put it in his pocket! QUEEN GERTRUDE No more! HAMLET A king of shreds and patches,-- Enter Ghost Save me, and hover o'er me with your wings, You heavenly guards! What would your gracious figure? QUEEN GERTRUDE Alas, he's mad! HAMLET Do you not come your tardy son to chide, That, lapsed in time and passion, lets go by The important acting of your dread command? O, say! Ghost Do not forget: this visitation Is but to whet thy almost blunted purpose. But, look, amazement on thy mother sits: O, step between her and her fighting soul: Conceit in weakest bodies strongest works: Speak to her, Hamlet. HAMLET How is it with you, lady? QUEEN GERTRUDE Alas, how is't with you, That you do bend your eye on vacancy And with the incorporal air do hold discourse? Forth at your eyes your spirits wildly peep; And, as the sleeping soldiers in the alarm, Your bedded hair, like life in excrements, Starts up, and stands on end. O gentle son, Upon the heat and flame of thy distemper Sprinkle cool patience. Whereon do you look? HAMLET On him, on him! Look you, how pale he glares! His form and cause conjoin'd, preaching to stones, Would make them capable. Do not look upon me; Lest with this piteous action you convert My stern effects: then what I have to do Will want true colour; tears perchance for blood. QUEEN GERTRUDE To whom do you speak this? HAMLET Do you see nothing there? QUEEN GERTRUDE Nothing at all; yet all that is I see. HAMLET Nor did you nothing hear? QUEEN GERTRUDE No, nothing but ourselves. HAMLET Why, look you there! look, how it steals away! My father, in his habit as he lived! Look, where he goes, even now, out at the portal! Exit Ghost QUEEN GERTRUDE This the very coinage of your brain: This bodiless creation ecstasy Is very cunning in. HAMLET Ecstasy! My pulse, as yours, doth temperately keep time, And makes as healthful music: it is not madness That I have utter'd: bring me to the test, And I the matter will re-word; which madness Would gambol from. Mother, for love of grace, Lay not that mattering unction to your soul, That not your trespass, but my madness speaks: It will but skin and film the ulcerous place, Whilst rank corruption, mining all within, Infects unseen. Confess yourself to heaven; Repent what's past; avoid what is to come; And do not spread the compost on the weeds, To make them ranker. Forgive me this my virtue; For in the fatness of these pursy times Virtue itself of vice must pardon beg, Yea, curb and woo for leave to do him good. QUEEN GERTRUDE O Hamlet, thou hast cleft my heart in twain. HAMLET O, throw away the worser part of it, And live the purer with the other half. Good night: but go not to mine uncle's bed; Assume a virtue, if you have it not. That monster, custom, who all sense doth eat, Of habits devil, is angel yet in this, That to the use of actions fair and good He likewise gives a frock or livery, That aptly is put on. Refrain to-night, And that shall lend a kind of easiness To the next abstinence: the next more easy; For use almost can change the stamp of nature, And either ... the devil, or throw him out With wondrous potency. Once more, good night: And when you are desirous to be bless'd, I'll blessing beg of you. For this same lord, Pointing to POLONIUS I do repent: but heaven hath pleased it so, To punish me with this and this with me, That I must be their scourge and minister. I will bestow him, and will answer well The death I gave him. So, again, good night. I must be cruel, only to be kind: Thus bad begins and worse remains behind. One word more, good lady. QUEEN GERTRUDE What shall I do? HAMLET Not this, by no means, that I bid you do: Let the bloat king tempt you again to bed; Pinch wanton on your cheek; call you his mouse; And let him, for a pair of reechy kisses, Or paddling in your neck with his damn'd fingers, Make you to ravel all this matter out, That I essentially am not in madness, But mad in craft. 'Twere good you let him know; For who, that's but a queen, fair, sober, wise, Would from a paddock, from a bat, a gib, Such dear concernings hide? who would do so? No, in despite of sense and secrecy, Unpeg the basket on the house's top. Let the birds fly, and, like the famous ape, To try conclusions, in the basket creep, And break your own neck down. QUEEN GERTRUDE Be thou assured, if words be made of breath, And breath of life, I have no life to breathe What thou hast said to me. HAMLET I must to England; you know that? QUEEN GERTRUDE Alack, I had forgot: 'tis so concluded on. HAMLET There's letters seal'd: and my two schoolfellows, Whom I will trust as I will adders fang'd, They bear the mandate; they must sweep my way, And marshal me to knavery. Let it work; For 'tis the sport to have the engineer Hoist with his own petard: and 't shall go hard But I will delve one yard below their mines, And blow them at the moon: O, 'tis most sweet, When in one line two crafts directly meet. This man shall set me packing: I'll lug the guts into the neighbour room. Mother, good night. Indeed this counsellor Is now most still, most secret and most grave, Who was in life a foolish prating knave. Come, sir, to draw toward an end with you. Good night, mother. Exeunt severally; HAMLET dragging in POLONIUS ACT IV SCENE I. A room in the castle. Enter KING CLAUDIUS, QUEEN GERTRUDE, ROSENCRANTZ, and GUILDENSTERN KING CLAUDIUS There's matter in these sighs, these profound heaves: You must translate: 'tis fit we understand them. Where is your son? QUEEN GERTRUDE Bestow this place on us a little while. Exeunt ROSENCRANTZ and GUILDENSTERN Ah, my good lord, what have I seen to-night! KING CLAUDIUS What, Gertrude? How does Hamlet? QUEEN GERTRUDE Mad as the sea and wind, when both contend Which is the mightier: in his lawless fit, Behind the arras hearing something stir, Whips out his rapier, cries, 'A rat, a rat!' And, in this brainish apprehension, kills The unseen good old man. KING CLAUDIUS O heavy deed! It had been so with us, had we been there: His liberty is full of threats to all; To you yourself, to us, to every one. Alas, how shall this bloody deed be answer'd? It will be laid to us, whose providence Should have kept short, restrain'd and out of haunt, This mad young man: but so much was our love, We would not understand what was most fit; But, like the owner of a foul disease, To keep it from divulging, let it feed Even on the pith of Life. Where is he gone? QUEEN GERTRUDE To draw apart the body he hath kill'd: O'er whom his very madness, like some ore Among a mineral of metals base, Shows itself pure; he weeps for what is done. KING CLAUDIUS O Gertrude, come away! The sun no sooner shall the mountains touch, But we will ship him hence: and this vile deed We must, with all our majesty and skill, Both countenance and excuse. Ho, Guildenstern! Re-enter ROSENCRANTZ and GUILDENSTERN Friends both, go join you with some further aid: Hamlet in madness hath Polonius slain, And from his mother's closet hath he dragg'd him: Go seek him out; speak fair, and bring the body Into the chapel. I pray you, haste in this. Exeunt ROSENCRANTZ and GUILDENSTERN Come, Gertrude, we'll call up our wisest friends; And let them know, both what we mean to do, And what's untimely done... Whose whisper o'er the world's diameter, As level as the cannon to his blank, Transports his poison'd shot, may miss our name, And hit the woundless air. O, come away! My soul is full of discord and dismay. Exeunt SCENE II. Another room in the castle. Enter HAMLET HAMLET Safely stowed. ROSENCRANTZ GUILDENSTERN Within Hamlet! Lord Hamlet! HAMLET What noise? who calls on Hamlet? O, here they come. Enter ROSENCRANTZ and GUILDENSTERN ROSENCRANTZ What have you done, my lord, with the dead body? HAMLET Compounded it with dust, whereto 'tis kin. ROSENCRANTZ Tell us where 'tis, that we may take it thence And bear it to the chapel. HAMLET Do not believe it. ROSENCRANTZ Believe what? HAMLET That I can keep your counsel and not mine own. Besides, to be demanded of a sponge! what replication should be made by the son of a king? ROSENCRANTZ Take you me for a sponge, my lord? HAMLET Ay, sir, that soaks up the king's countenance, his rewards, his authorities. But such officers do the king best service in the end: he keeps them, like an ape, in the corner of his jaw; first mouthed, to be last swallowed: when he needs what you have gleaned, it is but squeezing you, and, sponge, you shall be dry again. ROSENCRANTZ I understand you not, my lord. HAMLET I am glad of it: a knavish speech sleeps in a foolish ear. ROSENCRANTZ My lord, you must tell us where the body is, and go with us to the king. HAMLET The body is with the king, but the king is not with the body. The king is a thing-- GUILDENSTERN A thing, my lord! HAMLET Of nothing: bring me to him. Hide fox, and all after. Exeunt SCENE III. Another room in the castle. Enter KING CLAUDIUS, attended KING CLAUDIUS I have sent to seek him, and to find the body. How dangerous is it that this man goes loose! Yet must not we put the strong law on him: He's loved of the distracted multitude, Who like not in their judgment, but their eyes; And where tis so, the offender's scourge is weigh'd, But never the offence. To bear all smooth and even, This sudden sending him away must seem Deliberate pause: diseases desperate grown By desperate appliance are relieved, Or not at all. Enter ROSENCRANTZ How now! what hath befall'n? ROSENCRANTZ Where the dead body is bestow'd, my lord, We cannot get from him. KING CLAUDIUS But where is he? ROSENCRANTZ Without, my lord; guarded, to know your pleasure. KING CLAUDIUS Bring him before us. ROSENCRANTZ Ho, Guildenstern! bring in my lord. Enter HAMLET and GUILDENSTERN KING CLAUDIUS Now, Hamlet, where's Polonius? HAMLET At supper. KING CLAUDIUS At supper! where? HAMLET Not where he eats, but where he is eaten: a certain convocation of politic worms are e'en at him. Your worm is your only emperor for diet: we fat all creatures else to fat us, and we fat ourselves for maggots: your fat king and your lean beggar is but variable service, two dishes, but to one table: that's the end. KING CLAUDIUS Alas, alas! HAMLET A man may fish with the worm that hath eat of a king, and cat of the fish that hath fed of that worm. KING CLAUDIUS What dost you mean by this? HAMLET Nothing but to show you how a king may go a progress through the guts of a beggar. KING CLAUDIUS Where is Polonius? HAMLET In heaven; send hither to see: if your messenger find him not there, seek him i' the other place yourself. But indeed, if you find him not within this month, you shall nose him as you go up the stairs into the lobby. KING CLAUDIUS Go seek him there. To some Attendants HAMLET He will stay till ye come. Exeunt Attendants KING CLAUDIUS Hamlet, this deed, for thine especial safety,-- Which we do tender, as we dearly grieve For that which thou hast done,--must send thee hence With fiery quickness: therefore prepare thyself; The bark is ready, and the wind at help, The associates tend, and every thing is bent For England. HAMLET For England! KING CLAUDIUS Ay, Hamlet. HAMLET Good. KING CLAUDIUS So is it, if thou knew'st our purposes. HAMLET I see a cherub that sees them. But, come; for England! Farewell, dear mother. KING CLAUDIUS Thy loving father, Hamlet. HAMLET My mother: father and mother is man and wife; man and wife is one flesh; and so, my mother. Come, for England! Exit KING CLAUDIUS Follow him at foot; tempt him with speed aboard; Delay it not; I'll have him hence to-night: Away! for every thing is seal'd and done That else leans on the affair: pray you, make haste. Exeunt ROSENCRANTZ and GUILDENSTERN And, England, if my love thou hold'st at aught-- As my great power thereof may give thee sense, Since yet thy cicatrice looks raw and red After the Danish sword, and thy free awe Pays homage to us--thou mayst not coldly set Our sovereign process; which imports at full, By letters congruing to that effect, The present death of Hamlet. Do it, England; For like the hectic in my blood he rages, And thou must cure me: till I know 'tis done, Howe'er my haps, my joys were ne'er begun. Exit SCENE IV. A plain in Denmark. Enter FORTINBRAS, a Captain, and Soldiers, marching PRINCE FORTINBRAS Go, captain, from me greet the Danish king; Tell him that, by his licence, Fortinbras Craves the conveyance of a promised march Over his kingdom. You know the rendezvous. If that his majesty would aught with us, We shall express our duty in his eye; And let him know so. Captain I will do't, my lord. PRINCE FORTINBRAS Go softly on. Exeunt FORTINBRAS and Soldiers Enter HAMLET, ROSENCRANTZ, GUILDENSTERN, and others HAMLET Good sir, whose powers are these? Captain They are of Norway, sir. HAMLET How purposed, sir, I pray you? Captain Against some part of Poland. HAMLET Who commands them, sir? Captain The nephews to old Norway, Fortinbras. HAMLET Goes it against the main of Poland, sir, Or for some frontier? Captain Truly to speak, and with no addition, We go to gain a little patch of ground That hath in it no profit but the name. To pay five ducats, five, I would not farm it; Nor will it yield to Norway or the Pole A ranker rate, should it be sold in fee. HAMLET Why, then the Polack never will defend it. Captain Yes, it is already garrison'd. HAMLET Two thousand souls and twenty thousand ducats Will not debate the question of this straw: This is the imposthume of much wealth and peace, That inward breaks, and shows no cause without Why the man dies. I humbly thank you, sir. Captain God be wi' you, sir. Exit ROSENCRANTZ Wilt please you go, my lord? HAMLET I'll be with you straight go a little before. Exeunt all except HAMLET How all occasions do inform against me, And spur my dull revenge! What is a man, If his chief good and market of his time Be but to sleep and feed? a beast, no more. Sure, he that made us with such large discourse, Looking before and after, gave us not That capability and god-like reason To fust in us unused. Now, whether it be Bestial oblivion, or some craven scruple Of thinking too precisely on the event, A thought which, quarter'd, hath but one part wisdom And ever three parts coward, I do not know Why yet I live to say 'This thing's to do;' Sith I have cause and will and strength and means To do't. Examples gross as earth exhort me: Witness this army of such mass and charge Led by a delicate and tender prince, Whose spirit with divine ambition puff'd Makes mouths at the invisible event, Exposing what is mortal and unsure To all that fortune, death and danger dare, Even for an egg-shell. Rightly to be great Is not to stir without great argument, But greatly to find quarrel in a straw When honour's at the stake. How stand I then, That have a father kill'd, a mother stain'd, Excitements of my reason and my blood, And let all sleep? while, to my shame, I see The imminent death of twenty thousand men, That, for a fantasy and trick of fame, Go to their graves like beds, fight for a plot Whereon the numbers cannot try the cause, Which is not tomb enough and continent To hide the slain? O, from this time forth, My thoughts be bloody, or be nothing worth! Exit SCENE V. Elsinore. A room in the castle. Enter QUEEN GERTRUDE, HORATIO, and a Gentleman QUEEN GERTRUDE I will not speak with her. Gentleman She is importunate, indeed distract: Her mood will needs be pitied. QUEEN GERTRUDE What would she have? Gentleman She speaks much of her father; says she hears There's tricks i' the world; and hems, and beats her heart; Spurns enviously at straws; speaks things in doubt, That carry but half sense: her speech is nothing, Yet the unshaped use of it doth move The hearers to collection; they aim at it, And botch the words up fit to their own thoughts; Which, as her winks, and nods, and gestures yield them, Indeed would make one think there might be thought, Though nothing sure, yet much unhappily. HORATIO 'Twere good she were spoken with; for she may strew Dangerous conjectures in ill-breeding minds. QUEEN GERTRUDE Let her come in. Exit HORATIO To my sick soul, as sin's true nature is, Each toy seems prologue to some great amiss: So full of artless jealousy is guilt, It spills itself in fearing to be spilt. Re-enter HORATIO, with OPHELIA OPHELIA Where is the beauteous majesty of Denmark? QUEEN GERTRUDE How now, Ophelia! OPHELIA Sings How should I your true love know From another one? By his cockle hat and staff, And his sandal shoon. QUEEN GERTRUDE Alas, sweet lady, what imports this song? OPHELIA Say you? nay, pray you, mark. Sings He is dead and gone, lady, He is dead and gone; At his head a grass-green turf, At his heels a stone. QUEEN GERTRUDE Nay, but, Ophelia,-- OPHELIA Pray you, mark. Sings White his shroud as the mountain snow,-- Enter KING CLAUDIUS QUEEN GERTRUDE Alas, look here, my lord. OPHELIA Sings Larded with sweet flowers Which bewept to the grave did go With true-love showers. KING CLAUDIUS How do you, pretty lady? OPHELIA Well, God 'ild you! They say the owl was a baker's daughter. Lord, we know what we are, but know not what we may be. God be at your table! KING CLAUDIUS Conceit upon her father. OPHELIA Pray you, let's have no words of this; but when they ask you what it means, say you this: Sings To-morrow is Saint Valentine's day, All in the morning betime, And I a maid at your window, To be your Valentine. Then up he rose, and donn'd his clothes, And dupp'd the chamber-door; Let in the maid, that out a maid Never departed more. KING CLAUDIUS Pretty Ophelia! OPHELIA Indeed, la, without an oath, I'll make an end on't: Sings By Gis and by Saint Charity, Alack, and fie for shame! Young men will do't, if they come to't; By cock, they are to blame. Quoth she, before you tumbled me, You promised me to wed. So would I ha' done, by yonder sun, An thou hadst not come to my bed. KING CLAUDIUS How long hath she been thus? OPHELIA I hope all will be well. We must be patient: but I cannot choose but weep, to think they should lay him i' the cold ground. My brother shall know of it: and so I thank you for your good counsel. Come, my coach! Good night, ladies; good night, sweet ladies; good night, good night. Exit KING CLAUDIUS Follow her close; give her good watch, I pray you. Exit HORATIO O, this is the poison of deep grief; it springs All from her father's death. O Gertrude, Gertrude, When sorrows come, they come not single spies But in battalions. First, her father slain: Next, your son gone; and he most violent author Of his own just remove: the people muddied, Thick and unwholesome in their thoughts and whispers, For good Polonius' death; and we have done but greenly, In hugger-mugger to inter him: poor Ophelia Divided from herself and her fair judgment, Without the which we are pictures, or mere beasts: Last, and as much containing as all these, Her brother is in secret come from France; Feeds on his wonder, keeps himself in clouds, And wants not buzzers to infect his ear With pestilent speeches of his father's death; Wherein necessity, of matter beggar'd, Will nothing stick our person to arraign In ear and ear. O my dear Gertrude, this, Like to a murdering-piece, in many places Gives me superfluous death. A noise within QUEEN GERTRUDE Alack, what noise is this? KING CLAUDIUS Where are my Switzers? Let them guard the door. Enter another Gentleman What is the matter? Gentleman Save yourself, my lord: The ocean, overpeering of his list, Eats not the flats with more impetuous haste Than young Laertes, in a riotous head, O'erbears your officers. The rabble call him lord; And, as the world were now but to begin, Antiquity forgot, custom not known, The ratifiers and props of every word, They cry 'Choose we: Laertes shall be king:' Caps, hands, and tongues, applaud it to the clouds: 'Laertes shall be king, Laertes king!' QUEEN GERTRUDE How cheerfully on the false trail they cry! O, this is counter, you false Danish dogs! KING CLAUDIUS The doors are broke. Noise within Enter LAERTES, armed; Danes following LAERTES Where is this king? Sirs, stand you all without. Danes No, let's come in. LAERTES I pray you, give me leave. Danes We will, we will. They retire without the door LAERTES I thank you: keep the door. O thou vile king, Give me my father! QUEEN GERTRUDE Calmly, good Laertes. LAERTES That drop of blood that's calm proclaims me bastard, Cries cuckold to my father, brands the harlot Even here, between the chaste unsmirched brow Of my true mother. KING CLAUDIUS What is the cause, Laertes, That thy rebellion looks so giant-like? Let him go, Gertrude; do not fear our person: There's such divinity doth hedge a king, That treason can but peep to what it would, Acts little of his will. Tell me, Laertes, Why thou art thus incensed. Let him go, Gertrude. Speak, man. LAERTES Where is my father? KING CLAUDIUS Dead. QUEEN GERTRUDE But not by him. KING CLAUDIUS Let him demand his fill. LAERTES How came he dead? I'll not be juggled with: To hell, allegiance! vows, to the blackest devil! Conscience and grace, to the profoundest pit! I dare damnation. To this point I stand, That both the worlds I give to negligence, Let come what comes; only I'll be revenged Most thoroughly for my father. KING CLAUDIUS Who shall stay you? LAERTES My will, not all the world: And for my means, I'll husband them so well, They shall go far with little. KING CLAUDIUS Good Laertes, If you desire to know the certainty Of your dear father's death, is't writ in your revenge, That, swoopstake, you will draw both friend and foe, Winner and loser? LAERTES None but his enemies. KING CLAUDIUS Will you know them then? LAERTES To his good friends thus wide I'll ope my arms; And like the kind life-rendering pelican, Repast them with my blood. KING CLAUDIUS Why, now you speak Like a good child and a true gentleman. That I am guiltless of your father's death, And am most sensible in grief for it, It shall as level to your judgment pierce As day does to your eye. Danes Within Let her come in. LAERTES How now! what noise is that? Re-enter OPHELIA O heat, dry up my brains! tears seven times salt, Burn out the sense and virtue of mine eye! By heaven, thy madness shall be paid by weight, Till our scale turn the beam. O rose of May! Dear maid, kind sister, sweet Ophelia! O heavens! is't possible, a young maid's wits Should be as moral as an old man's life? Nature is fine in love, and where 'tis fine, It sends some precious instance of itself After the thing it loves. OPHELIA Sings They bore him barefaced on the bier; Hey non nonny, nonny, hey nonny; And in his grave rain'd many a tear:-- Fare you well, my dove! LAERTES Hadst thou thy wits, and didst persuade revenge, It could not move thus. OPHELIA Sings You must sing a-down a-down, An you call him a-down-a. O, how the wheel becomes it! It is the false steward, that stole his master's daughter. LAERTES This nothing's more than matter. OPHELIA There's rosemary, that's for remembrance; pray, love, remember: and there is pansies. that's for thoughts. LAERTES A document in madness, thoughts and remembrance fitted. OPHELIA There's fennel for you, and columbines: there's rue for you; and here's some for me: we may call it herb-grace o' Sundays: O you must wear your rue with a difference. There's a daisy: I would give you some violets, but they withered all when my father died: they say he made a good end,-- Sings For bonny sweet Robin is all my joy. LAERTES Thought and affliction, passion, hell itself, She turns to favour and to prettiness. OPHELIA Sings And will he not come again? And will he not come again? No, no, he is dead: Go to thy death-bed: He never will come again. His beard was as white as snow, All flaxen was his poll: He is gone, he is gone, And we cast away moan: God ha' mercy on his soul! And of all Christian souls, I pray God. God be wi' ye. Exit LAERTES Do you see this, O God? KING CLAUDIUS Laertes, I must commune with your grief, Or you deny me right. Go but apart, Make choice of whom your wisest friends you will. And they shall hear and judge 'twixt you and me: If by direct or by collateral hand They find us touch'd, we will our kingdom give, Our crown, our life, and all that we can ours, To you in satisfaction; but if not, Be you content to lend your patience to us, And we shall jointly labour with your soul To give it due content. LAERTES Let this be so; His means of death, his obscure funeral-- No trophy, sword, nor hatchment o'er his bones, No noble rite nor formal ostentation-- Cry to be heard, as 'twere from heaven to earth, That I must call't in question. KING CLAUDIUS So you shall; And where the offence is let the great axe fall. I pray you, go with me. Exeunt SCENE VI. Another room in the castle. Enter HORATIO and a Servant HORATIO What are they that would speak with me? Servant Sailors, sir: they say they have letters for you. HORATIO Let them come in. Exit Servant I do not know from what part of the world I should be greeted, if not from Lord Hamlet. Enter Sailors First Sailor God bless you, sir. HORATIO Let him bless thee too. First Sailor He shall, sir, an't please him. There's a letter for you, sir; it comes from the ambassador that was bound for England; if your name be Horatio, as I am let to know it is. HORATIO Reads 'Horatio, when thou shalt have overlooked this, give these fellows some means to the king: they have letters for him. Ere we were two days old at sea, a pirate of very warlike appointment gave us chase. Finding ourselves too slow of sail, we put on a compelled valour, and in the grapple I boarded them: on the instant they got clear of our ship; so I alone became their prisoner. They have dealt with me like thieves of mercy: but they knew what they did; I am to do a good turn for them. Let the king have the letters I have sent; and repair thou to me with as much speed as thou wouldst fly death. I have words to speak in thine ear will make thee dumb; yet are they much too light for the bore of the matter. These good fellows will bring thee where I am. Rosencrantz and Guildenstern hold their course for England: of them I have much to tell thee. Farewell. 'He that thou knowest thine, HAMLET.' Come, I will make you way for these your letters; And do't the speedier, that you may direct me To him from whom you brought them. Exeunt SCENE VII. Another room in the castle. Enter KING CLAUDIUS and LAERTES KING CLAUDIUS Now must your conscience my acquaintance seal, And you must put me in your heart for friend, Sith you have heard, and with a knowing ear, That he which hath your noble father slain Pursued my life. LAERTES It well appears: but tell me Why you proceeded not against these feats, So crimeful and so capital in nature, As by your safety, wisdom, all things else, You mainly were stirr'd up. KING CLAUDIUS O, for two special reasons; Which may to you, perhaps, seem much unsinew'd, But yet to me they are strong. The queen his mother Lives almost by his looks; and for myself-- My virtue or my plague, be it either which-- She's so conjunctive to my life and soul, That, as the star moves not but in his sphere, I could not but by her. The other motive, Why to a public count I might not go, Is the great love the general gender bear him; Who, dipping all his faults in their affection, Would, like the spring that turneth wood to stone, Convert his gyves to graces; so that my arrows, Too slightly timber'd for so loud a wind, Would have reverted to my bow again, And not where I had aim'd them. LAERTES And so have I a noble father lost; A sister driven into desperate terms, Whose worth, if praises may go back again, Stood challenger on mount of all the age For her perfections: but my revenge will come. KING CLAUDIUS Break not your sleeps for that: you must not think That we are made of stuff so flat and dull That we can let our beard be shook with danger And think it pastime. You shortly shall hear more: I loved your father, and we love ourself; And that, I hope, will teach you to imagine-- Enter a Messenger How now! what news? Messenger Letters, my lord, from Hamlet: This to your majesty; this to the queen. KING CLAUDIUS From Hamlet! who brought them? Messenger Sailors, my lord, they say; I saw them not: They were given me by Claudio; he received them Of him that brought them. KING CLAUDIUS Laertes, you shall hear them. Leave us. Exit Messenger Reads 'High and mighty, You shall know I am set naked on your kingdom. To-morrow shall I beg leave to see your kingly eyes: when I shall, first asking your pardon thereunto, recount the occasion of my sudden and more strange return. 'HAMLET.' What should this mean? Are all the rest come back? Or is it some abuse, and no such thing? LAERTES Know you the hand? KING CLAUDIUS 'Tis Hamlets character. 'Naked! And in a postscript here, he says 'alone.' Can you advise me? LAERTES I'm lost in it, my lord. But let him come; It warms the very sickness in my heart, That I shall live and tell him to his teeth, 'Thus didest thou.' KING CLAUDIUS If it be so, Laertes-- As how should it be so? how otherwise?-- Will you be ruled by me? LAERTES Ay, my lord; So you will not o'errule me to a peace. KING CLAUDIUS To thine own peace. If he be now return'd, As checking at his voyage, and that he means No more to undertake it, I will work him To an exploit, now ripe in my device, Under the which he shall not choose but fall: And for his death no wind of blame shall breathe, But even his mother shall uncharge the practise And call it accident. LAERTES My lord, I will be ruled; The rather, if you could devise it so That I might be the organ. KING CLAUDIUS It falls right. You have been talk'd of since your travel much, And that in Hamlet's hearing, for a quality Wherein, they say, you shine: your sum of parts Did not together pluck such envy from him As did that one, and that, in my regard, Of the unworthiest siege. LAERTES What part is that, my lord? KING CLAUDIUS A very riband in the cap of youth, Yet needful too; for youth no less becomes The light and careless livery that it wears Than settled age his sables and his weeds, Importing health and graveness. Two months since, Here was a gentleman of Normandy:-- I've seen myself, and served against, the French, And they can well on horseback: but this gallant Had witchcraft in't; he grew unto his seat; And to such wondrous doing brought his horse, As he had been incorpsed and demi-natured With the brave beast: so far he topp'd my thought, That I, in forgery of shapes and tricks, Come short of what he did. LAERTES A Norman was't? KING CLAUDIUS A Norman. LAERTES Upon my life, Lamond. KING CLAUDIUS The very same. LAERTES I know him well: he is the brooch indeed And gem of all the nation. KING CLAUDIUS He made confession of you, And gave you such a masterly report For art and exercise in your defence And for your rapier most especially, That he cried out, 'twould be a sight indeed, If one could match you: the scrimers of their nation, He swore, had had neither motion, guard, nor eye, If you opposed them. Sir, this report of his Did Hamlet so envenom with his envy That he could nothing do but wish and beg Your sudden coming o'er, to play with him. Now, out of this,-- LAERTES What out of this, my lord? KING CLAUDIUS Laertes, was your father dear to you? Or are you like the painting of a sorrow, A face without a heart? LAERTES Why ask you this? KING CLAUDIUS Not that I think you did not love your father; But that I know love is begun by time; And that I see, in passages of proof, Time qualifies the spark and fire of it. There lives within the very flame of love A kind of wick or snuff that will abate it; And nothing is at a like goodness still; For goodness, growing to a plurisy, Dies in his own too much: that we would do We should do when we would; for this 'would' changes And hath abatements and delays as many As there are tongues, are hands, are accidents; And then this 'should' is like a spendthrift sigh, That hurts by easing. But, to the quick o' the ulcer:-- Hamlet comes back: what would you undertake, To show yourself your father's son in deed More than in words? LAERTES To cut his throat i' the church. KING CLAUDIUS No place, indeed, should murder sanctuarize; Revenge should have no bounds. But, good Laertes, Will you do this, keep close within your chamber. Hamlet return'd shall know you are come home: We'll put on those shall praise your excellence And set a double varnish on the fame The Frenchman gave you, bring you in fine together And wager on your heads: he, being remiss, Most generous and free from all contriving, Will not peruse the foils; so that, with ease, Or with a little shuffling, you may choose A sword unbated, and in a pass of practise Requite him for your father. LAERTES I will do't: And, for that purpose, I'll anoint my sword. I bought an unction of a mountebank, So mortal that, but dip a knife in it, Where it draws blood no cataplasm so rare, Collected from all simples that have virtue Under the moon, can save the thing from death That is but scratch'd withal: I'll touch my point With this contagion, that, if I gall him slightly, It may be death. KING CLAUDIUS Let's further think of this; Weigh what convenience both of time and means May fit us to our shape: if this should fail, And that our drift look through our bad performance, 'Twere better not assay'd: therefore this project Should have a back or second, that might hold, If this should blast in proof. Soft! let me see: We'll make a solemn wager on your cunnings: I ha't. When in your motion you are hot and dry-- As make your bouts more violent to that end-- And that he calls for drink, I'll have prepared him A chalice for the nonce, whereon but sipping, If he by chance escape your venom'd stuck, Our purpose may hold there. Enter QUEEN GERTRUDE How now, sweet queen! QUEEN GERTRUDE One woe doth tread upon another's heel, So fast they follow; your sister's drown'd, Laertes. LAERTES Drown'd! O, where? QUEEN GERTRUDE There is a willow grows aslant a brook, That shows his hoar leaves in the glassy stream; There with fantastic garlands did she come Of crow-flowers, nettles, daisies, and long purples That liberal shepherds give a grosser name, But our cold maids do dead men's fingers call them: There, on the pendent boughs her coronet weeds Clambering to hang, an envious sliver broke; When down her weedy trophies and herself Fell in the weeping brook. Her clothes spread wide; And, mermaid-like, awhile they bore her up: Which time she chanted snatches of old tunes; As one incapable of her own distress, Or like a creature native and indued Unto that element: but long it could not be Till that her garments, heavy with their drink, Pull'd the poor wretch from her melodious lay To muddy death. LAERTES Alas, then, she is drown'd? QUEEN GERTRUDE Drown'd, drown'd. LAERTES Too much of water hast thou, poor Ophelia, And therefore I forbid my tears: but yet It is our trick; nature her custom holds, Let shame say what it will: when these are gone, The woman will be out. Adieu, my lord: I have a speech of fire, that fain would blaze, But that this folly douts it. Exit KING CLAUDIUS Let's follow, Gertrude: How much I had to do to calm his rage! Now fear I this will give it start again; Therefore let's follow. Exeunt ACT V SCENE I. A churchyard. Enter two Clowns, with spades, &c First Clown Is she to be buried in Christian burial that wilfully seeks her own salvation? Second Clown I tell thee she is: and therefore make her grave straight: the crowner hath sat on her, and finds it Christian burial. First Clown How can that be, unless she drowned herself in her own defence? Second Clown Why, 'tis found so. First Clown It must be 'se offendendo;' it cannot be else. For here lies the point: if I drown myself wittingly, it argues an act: and an act hath three branches: it is, to act, to do, to perform: argal, she drowned herself wittingly. Second Clown Nay, but hear you, goodman delver,-- First Clown Give me leave. Here lies the water; good: here stands the man; good; if the man go to this water, and drown himself, it is, will he, nill he, he goes,--mark you that; but if the water come to him and drown him, he drowns not himself: argal, he that is not guilty of his own death shortens not his own life. Second Clown But is this law? First Clown Ay, marry, is't; crowner's quest law. Second Clown Will you ha' the truth on't? If this had not been a gentlewoman, she should have been buried out o' Christian burial. First Clown Why, there thou say'st: and the more pity that great folk should have countenance in this world to drown or hang themselves, more than their even Christian. Come, my spade. There is no ancient gentleman but gardeners, ditchers, and grave-makers: they hold up Adam's profession. Second Clown Was he a gentleman? First Clown He was the first that ever bore arms. Second Clown Why, he had none. First Clown What, art a heathen? How dost thou understand the Scripture? The Scripture says 'Adam digged:' could he dig without arms? I'll put another question to thee: if thou answerest me not to the purpose, confess thyself-- Second Clown Go to. First Clown What is he that builds stronger than either the mason, the shipwright, or the carpenter? Second Clown The gallows-maker; for that frame outlives a thousand tenants. First Clown I like thy wit well, in good faith: the gallows does well; but how does it well? it does well to those that do in: now thou dost ill to say the gallows is built stronger than the church: argal, the gallows may do well to thee. To't again, come. Second Clown 'Who builds stronger than a mason, a shipwright, or a carpenter?' First Clown Ay, tell me that, and unyoke. Second Clown Marry, now I can tell. First Clown To't. Second Clown Mass, I cannot tell. Enter HAMLET and HORATIO, at a distance First Clown Cudgel thy brains no more about it, for your dull ass will not mend his pace with beating; and, when you are asked this question next, say 'a grave-maker: 'the houses that he makes last till doomsday. Go, get thee to Yaughan: fetch me a stoup of liquor. Exit Second Clown He digs and sings In youth, when I did love, did love, Methought it was very sweet, To contract, O, the time, for, ah, my behove, O, methought, there was nothing meet. HAMLET Has this fellow no feeling of his business, that he sings at grave-making? HORATIO Custom hath made it in him a property of easiness. HAMLET 'Tis e'en so: the hand of little employment hath the daintier sense. First Clown Sings But age, with his stealing steps, Hath claw'd me in his clutch, And hath shipped me intil the land, As if I had never been such. Throws up a skull HAMLET That skull had a tongue in it, and could sing once: how the knave jowls it to the ground, as if it were Cain's jaw-bone, that did the first murder! It might be the pate of a politician, which this ass now o'er-reaches; one that would circumvent God, might it not? HORATIO It might, my lord. HAMLET Or of a courtier; which could say 'Good morrow, sweet lord! How dost thou, good lord?' This might be my lord such-a-one, that praised my lord such-a-one's horse, when he meant to beg it; might it not? HORATIO Ay, my lord. HAMLET Why, e'en so: and now my Lady Worm's; chapless, and knocked about the mazzard with a sexton's spade: here's fine revolution, an we had the trick to see't. Did these bones cost no more the breeding, but to play at loggats with 'em? mine ache to think on't. First Clown Sings A pick-axe, and a spade, a spade, For and a shrouding sheet: O, a pit of clay for to be made For such a guest is meet. Throws up another skull HAMLET There's another: why may not that be the skull of a lawyer? Where be his quiddities now, his quillets, his cases, his tenures, and his tricks? why does he suffer this rude knave now to knock him about the sconce with a dirty shovel, and will not tell him of his action of battery? Hum! This fellow might be in's time a great buyer of land, with his statutes, his recognizances, his fines, his double vouchers, his recoveries: is this the fine of his fines, and the recovery of his recoveries, to have his fine pate full of fine dirt? will his vouchers vouch him no more of his purchases, and double ones too, than the length and breadth of a pair of indentures? The very conveyances of his lands will hardly lie in this box; and must the inheritor himself have no more, ha? HORATIO Not a jot more, my lord. HAMLET Is not parchment made of sheepskins? HORATIO Ay, my lord, and of calf-skins too. HAMLET They are sheep and calves which seek out assurance in that. I will speak to this fellow. Whose grave's this, sirrah? First Clown Mine, sir. Sings O, a pit of clay for to be made For such a guest is meet. HAMLET I think it be thine, indeed; for thou liest in't. First Clown You lie out on't, sir, and therefore it is not yours: for my part, I do not lie in't, and yet it is mine. HAMLET 'Thou dost lie in't, to be in't and say it is thine: 'tis for the dead, not for the quick; therefore thou liest. First Clown 'Tis a quick lie, sir; 'twill away gain, from me to you. HAMLET What man dost thou dig it for? First Clown For no man, sir. HAMLET What woman, then? First Clown For none, neither. HAMLET Who is to be buried in't? First Clown One that was a woman, sir; but, rest her soul, she's dead. HAMLET How absolute the knave is! we must speak by the card, or equivocation will undo us. By the Lord, Horatio, these three years I have taken a note of it; the age is grown so picked that the toe of the peasant comes so near the heel of the courtier, he gaffs his kibe. How long hast thou been a grave-maker? First Clown Of all the days i' the year, I came to't that day that our last king Hamlet overcame Fortinbras. HAMLET How long is that since? First Clown Cannot you tell that? every fool can tell that: it was the very day that young Hamlet was born; he that is mad, and sent into England. HAMLET Ay, marry, why was he sent into England? First Clown Why, because he was mad: he shall recover his wits there; or, if he do not, it's no great matter there. HAMLET Why? First Clown 'Twill, a not be seen in him there; there the men are as mad as he. HAMLET How came he mad? First Clown Very strangely, they say. HAMLET How strangely? First Clown Faith, e'en with losing his wits. HAMLET Upon what ground? First Clown Why, here in Denmark: I have been sexton here, man and boy, thirty years. HAMLET How long will a man lie i' the earth ere he rot? First Clown I' faith, if he be not rotten before he die--as we have many pocky corses now-a-days, that will scarce hold the laying in--he will last you some eight year or nine year: a tanner will last you nine year. HAMLET Why he more than another? First Clown Why, sir, his hide is so tanned with his trade, that he will keep out water a great while; and your water is a sore decayer of your whoreson dead body. Here's a skull now; this skull has lain in the earth three and twenty years. HAMLET Whose was it? First Clown A whoreson mad fellow's it was: whose do you think it was? HAMLET Nay, I know not. First Clown A pestilence on him for a mad rogue! a' poured a flagon of Rhenish on my head once. This same skull, sir, was Yorick's skull, the king's jester. HAMLET This? First Clown E'en that. HAMLET Let me see. Takes the skull Alas, poor Yorick! I knew him, Horatio: a fellow of infinite jest, of most excellent fancy: he hath borne me on his back a thousand times; and now, how abhorred in my imagination it is! my gorge rims at it. Here hung those lips that I have kissed I know not how oft. Where be your gibes now? your gambols? your songs? your flashes of merriment, that were wont to set the table on a roar? Not one now, to mock your own grinning? quite chap-fallen? Now get you to my lady's chamber, and tell her, let her paint an inch thick, to this favour she must come; make her laugh at that. Prithee, Horatio, tell me one thing. HORATIO What's that, my lord? HAMLET Dost thou think Alexander looked o' this fashion i' the earth? HORATIO E'en so. HAMLET And smelt so? pah! Puts down the skull HORATIO E'en so, my lord. HAMLET To what base uses we may return, Horatio! Why may not imagination trace the noble dust of Alexander, till he find it stopping a bung-hole? HORATIO 'Twere to consider too curiously, to consider so. HAMLET No, faith, not a jot; but to follow him thither with modesty enough, and likelihood to lead it: as thus: Alexander died, Alexander was buried, Alexander returneth into dust; the dust is earth; of earth we make loam; and why of that loam, whereto he was converted, might they not stop a beer-barrel? Imperious Caesar, dead and turn'd to clay, Might stop a hole to keep the wind away: O, that that earth, which kept the world in awe, Should patch a wall to expel the winter flaw! But soft! but soft! aside: here comes the king. Enter Priest, &c. in procession; the Corpse of OPHELIA, LAERTES and Mourners following; KING CLAUDIUS, QUEEN GERTRUDE, their trains, &c The queen, the courtiers: who is this they follow? And with such maimed rites? This doth betoken The corse they follow did with desperate hand Fordo its own life: 'twas of some estate. Couch we awhile, and mark. Retiring with HORATIO LAERTES What ceremony else? HAMLET That is Laertes, A very noble youth: mark. LAERTES What ceremony else? First Priest Her obsequies have been as far enlarged As we have warrantise: her death was doubtful; And, but that great command o'ersways the order, She should in ground unsanctified have lodged Till the last trumpet: for charitable prayers, Shards, flints and pebbles should be thrown on her; Yet here she is allow'd her virgin crants, Her maiden strewments and the bringing home Of bell and burial. LAERTES Must there no more be done? First Priest No more be done: We should profane the service of the dead To sing a requiem and such rest to her As to peace-parted souls. LAERTES Lay her i' the earth: And from her fair and unpolluted flesh May violets spring! I tell thee, churlish priest, A ministering angel shall my sister be, When thou liest howling. HAMLET What, the fair Ophelia! QUEEN GERTRUDE Sweets to the sweet: farewell! Scattering flowers I hoped thou shouldst have been my Hamlet's wife; I thought thy bride-bed to have deck'd, sweet maid, And not have strew'd thy grave. LAERTES O, treble woe Fall ten times treble on that cursed head, Whose wicked deed thy most ingenious sense Deprived thee of! Hold off the earth awhile, Till I have caught her once more in mine arms: Leaps into the grave Now pile your dust upon the quick and dead, Till of this flat a mountain you have made, To o'ertop old Pelion, or the skyish head Of blue Olympus. HAMLET Advancing What is he whose grief Bears such an emphasis? whose phrase of sorrow Conjures the wandering stars, and makes them stand Like wonder-wounded hearers? This is I, Hamlet the Dane. Leaps into the grave LAERTES The devil take thy soul! Grappling with him HAMLET Thou pray'st not well. I prithee, take thy fingers from my throat; For, though I am not splenitive and rash, Yet have I something in me dangerous, Which let thy wiseness fear: hold off thy hand. KING CLAUDIUS Pluck them asunder. QUEEN GERTRUDE Hamlet, Hamlet! All Gentlemen,-- HORATIO Good my lord, be quiet. The Attendants part them, and they come out of the grave HAMLET Why I will fight with him upon this theme Until my eyelids will no longer wag. QUEEN GERTRUDE O my son, what theme? HAMLET I loved Ophelia: forty thousand brothers Could not, with all their quantity of love, Make up my sum. What wilt thou do for her? KING CLAUDIUS O, he is mad, Laertes. QUEEN GERTRUDE For love of God, forbear him. HAMLET 'Swounds, show me what thou'lt do: Woo't weep? woo't fight? woo't fast? woo't tear thyself? Woo't drink up eisel? eat a crocodile? I'll do't. Dost thou come here to whine? To outface me with leaping in her grave? Be buried quick with her, and so will I: And, if thou prate of mountains, let them throw Millions of acres on us, till our ground, Singeing his pate against the burning zone, Make Ossa like a wart! Nay, an thou'lt mouth, I'll rant as well as thou. QUEEN GERTRUDE This is mere madness: And thus awhile the fit will work on him; Anon, as patient as the female dove, When that her golden couplets are disclosed, His silence will sit drooping. HAMLET Hear you, sir; What is the reason that you use me thus? I loved you ever: but it is no matter; Let Hercules himself do what he may, The cat will mew and dog will have his day. Exit KING CLAUDIUS I pray you, good Horatio, wait upon him. Exit HORATIO To LAERTES Strengthen your patience in our last night's speech; We'll put the matter to the present push. Good Gertrude, set some watch over your son. This grave shall have a living monument: An hour of quiet shortly shall we see; Till then, in patience our proceeding be. Exeunt SCENE II. A hall in the castle. Enter HAMLET and HORATIO HAMLET So much for this, sir: now shall you see the other; You do remember all the circumstance? HORATIO Remember it, my lord? HAMLET Sir, in my heart there was a kind of fighting, That would not let me sleep: methought I lay Worse than the mutines in the bilboes. Rashly, And praised be rashness for it, let us know, Our indiscretion sometimes serves us well, When our deep plots do pall: and that should teach us There's a divinity that shapes our ends, Rough-hew them how we will,-- HORATIO That is most certain. HAMLET Up from my cabin, My sea-gown scarf'd about me, in the dark Groped I to find out them; had my desire. Finger'd their packet, and in fine withdrew To mine own room again; making so bold, My fears forgetting manners, to unseal Their grand commission; where I found, Horatio,-- O royal knavery!--an exact command, Larded with many several sorts of reasons Importing Denmark's health and England's too, With, ho! such bugs and goblins in my life, That, on the supervise, no leisure bated, No, not to stay the grinding of the axe, My head should be struck off. HORATIO Is't possible? HAMLET Here's the commission: read it at more leisure. But wilt thou hear me how I did proceed? HORATIO I beseech you. HAMLET Being thus be-netted round with villanies,-- Ere I could make a prologue to my brains, They had begun the play--I sat me down, Devised a new commission, wrote it fair: I once did hold it, as our statists do, A baseness to write fair and labour'd much How to forget that learning, but, sir, now It did me yeoman's service: wilt thou know The effect of what I wrote? HORATIO Ay, good my lord. HAMLET An earnest conjuration from the king, As England was his faithful tributary, As love between them like the palm might flourish, As peace should stiff her wheaten garland wear And stand a comma 'tween their amities, And many such-like 'As'es of great charge, That, on the view and knowing of these contents, Without debatement further, more or less, He should the bearers put to sudden death, Not shriving-time allow'd. HORATIO How was this seal'd? HAMLET Why, even in that was heaven ordinant. I had my father's signet in my purse, Which was the model of that Danish seal; Folded the writ up in form of the other, Subscribed it, gave't the impression, placed it safely, The changeling never known. Now, the next day Was our sea-fight; and what to this was sequent Thou know'st already. HORATIO So Guildenstern and Rosencrantz go to't. HAMLET Why, man, they did make love to this employment; They are not near my conscience; their defeat Does by their own insinuation grow: 'Tis dangerous when the baser nature comes Between the pass and fell incensed points Of mighty opposites. HORATIO Why, what a king is this! HAMLET Does it not, think'st thee, stand me now upon-- He that hath kill'd my king and whored my mother, Popp'd in between the election and my hopes, Thrown out his angle for my proper life, And with such cozenage--is't not perfect conscience, To quit him with this arm? and is't not to be damn'd, To let this canker of our nature come In further evil? HORATIO It must be shortly known to him from England What is the issue of the business there. HAMLET It will be short: the interim is mine; And a man's life's no more than to say 'One.' But I am very sorry, good Horatio, That to Laertes I forgot myself; For, by the image of my cause, I see The portraiture of his: I'll court his favours. But, sure, the bravery of his grief did put me Into a towering passion. HORATIO Peace! who comes here? Enter OSRIC OSRIC Your lordship is right welcome back to Denmark. HAMLET I humbly thank you, sir. Dost know this water-fly? HORATIO No, my good lord. HAMLET Thy state is the more gracious; for 'tis a vice to know him. He hath much land, and fertile: let a beast be lord of beasts, and his crib shall stand at the king's mess: 'tis a chough; but, as I say, spacious in the possession of dirt. OSRIC Sweet lord, if your lordship were at leisure, I should impart a thing to you from his majesty. HAMLET I will receive it, sir, with all diligence of spirit. Put your bonnet to his right use; 'tis for the head. OSRIC I thank your lordship, it is very hot. HAMLET No, believe me, 'tis very cold; the wind is northerly. OSRIC It is indifferent cold, my lord, indeed. HAMLET But yet methinks it is very sultry and hot for my complexion. OSRIC Exceedingly, my lord; it is very sultry,--as 'twere,--I cannot tell how. But, my lord, his majesty bade me signify to you that he has laid a great wager on your head: sir, this is the matter,-- HAMLET I beseech you, remember-- HAMLET moves him to put on his hat OSRIC Nay, good my lord; for mine ease, in good faith. Sir, here is newly come to court Laertes; believe me, an absolute gentleman, full of most excellent differences, of very soft society and great showing: indeed, to speak feelingly of him, he is the card or calendar of gentry, for you shall find in him the continent of what part a gentleman would see. HAMLET Sir, his definement suffers no perdition in you; though, I know, to divide him inventorially would dizzy the arithmetic of memory, and yet but yaw neither, in respect of his quick sail. But, in the verity of extolment, I take him to be a soul of great article; and his infusion of such dearth and rareness, as, to make true diction of him, his semblable is his mirror; and who else would trace him, his umbrage, nothing more. OSRIC Your lordship speaks most infallibly of him. HAMLET The concernancy, sir? why do we wrap the gentleman in our more rawer breath? OSRIC Sir? HORATIO Is't not possible to understand in another tongue? You will do't, sir, really. HAMLET What imports the nomination of this gentleman? OSRIC Of Laertes? HORATIO His purse is empty already; all's golden words are spent. HAMLET Of him, sir. OSRIC I know you are not ignorant-- HAMLET I would you did, sir; yet, in faith, if you did, it would not much approve me. Well, sir? OSRIC You are not ignorant of what excellence Laertes is-- HAMLET I dare not confess that, lest I should compare with him in excellence; but, to know a man well, were to know himself. OSRIC I mean, sir, for his weapon; but in the imputation laid on him by them, in his meed he's unfellowed. HAMLET What's his weapon? OSRIC Rapier and dagger. HAMLET That's two of his weapons: but, well. OSRIC The king, sir, hath wagered with him six Barbary horses: against the which he has imponed, as I take it, six French rapiers and poniards, with their assigns, as girdle, hangers, and so: three of the carriages, in faith, are very dear to fancy, very responsive to the hilts, most delicate carriages, and of very liberal conceit. HAMLET What call you the carriages? HORATIO I knew you must be edified by the margent ere you had done. OSRIC The carriages, sir, are the hangers. HAMLET The phrase would be more german to the matter, if we could carry cannon by our sides: I would it might be hangers till then. But, on: six Barbary horses against six French swords, their assigns, and three liberal-conceited carriages; that's the French bet against the Danish. Why is this 'imponed,' as you call it? OSRIC The king, sir, hath laid, that in a dozen passes between yourself and him, he shall not exceed you three hits: he hath laid on twelve for nine; and it would come to immediate trial, if your lordship would vouchsafe the answer. HAMLET How if I answer 'no'? OSRIC I mean, my lord, the opposition of your person in trial. HAMLET Sir, I will walk here in the hall: if it please his majesty, 'tis the breathing time of day with me; let the foils be brought, the gentleman willing, and the king hold his purpose, I will win for him an I can; if not, I will gain nothing but my shame and the odd hits. OSRIC Shall I re-deliver you e'en so? HAMLET To this effect, sir; after what flourish your nature will. OSRIC I commend my duty to your lordship. HAMLET Yours, yours. Exit OSRIC He does well to commend it himself; there are no tongues else for's turn. HORATIO This lapwing runs away with the shell on his head. HAMLET He did comply with his dug, before he sucked it. Thus has he--and many more of the same bevy that I know the dressy age dotes on--only got the tune of the time and outward habit of encounter; a kind of yesty collection, which carries them through and through the most fond and winnowed opinions; and do but blow them to their trial, the bubbles are out. Enter a Lord Lord My lord, his majesty commended him to you by young Osric, who brings back to him that you attend him in the hall: he sends to know if your pleasure hold to play with Laertes, or that you will take longer time. HAMLET I am constant to my purpose; they follow the king's pleasure: if his fitness speaks, mine is ready; now or whensoever, provided I be so able as now. Lord The king and queen and all are coming down. HAMLET In happy time. Lord The queen desires you to use some gentle entertainment to Laertes before you fall to play. HAMLET She well instructs me. Exit Lord HORATIO You will lose this wager, my lord. HAMLET I do not think so: since he went into France, I have been in continual practise: I shall win at the odds. But thou wouldst not think how ill all's here about my heart: but it is no matter. HORATIO Nay, good my lord,-- HAMLET It is but foolery; but it is such a kind of gain-giving, as would perhaps trouble a woman. HORATIO If your mind dislike any thing, obey it: I will forestall their repair hither, and say you are not fit. HAMLET Not a whit, we defy augury: there's a special providence in the fall of a sparrow. If it be now, 'tis not to come; if it be not to come, it will be now; if it be not now, yet it will come: the readiness is all: since no man has aught of what he leaves, what is't to leave betimes? Enter KING CLAUDIUS, QUEEN GERTRUDE, LAERTES, Lords, OSRIC, and Attendants with foils, &c KING CLAUDIUS Come, Hamlet, come, and take this hand from me. KING CLAUDIUS puts LAERTES' hand into HAMLET's HAMLET Give me your pardon, sir: I've done you wrong; But pardon't, as you are a gentleman. This presence knows, And you must needs have heard, how I am punish'd With sore distraction. What I have done, That might your nature, honour and exception Roughly awake, I here proclaim was madness. Was't Hamlet wrong'd Laertes? Never Hamlet: If Hamlet from himself be ta'en away, And when he's not himself does wrong Laertes, Then Hamlet does it not, Hamlet denies it. Who does it, then? His madness: if't be so, Hamlet is of the faction that is wrong'd; His madness is poor Hamlet's enemy. Sir, in this audience, Let my disclaiming from a purposed evil Free me so far in your most generous thoughts, That I have shot mine arrow o'er the house, And hurt my brother. LAERTES I am satisfied in nature, Whose motive, in this case, should stir me most To my revenge: but in my terms of honour I stand aloof; and will no reconcilement, Till by some elder masters, of known honour, I have a voice and precedent of peace, To keep my name ungored. But till that time, I do receive your offer'd love like love, And will not wrong it. HAMLET I embrace it freely; And will this brother's wager frankly play. Give us the foils. Come on. LAERTES Come, one for me. HAMLET I'll be your foil, Laertes: in mine ignorance Your skill shall, like a star i' the darkest night, Stick fiery off indeed. LAERTES You mock me, sir. HAMLET No, by this hand. KING CLAUDIUS Give them the foils, young Osric. Cousin Hamlet, You know the wager? HAMLET Very well, my lord Your grace hath laid the odds o' the weaker side. KING CLAUDIUS I do not fear it; I have seen you both: But since he is better'd, we have therefore odds. LAERTES This is too heavy, let me see another. HAMLET This likes me well. These foils have all a length? They prepare to play OSRIC Ay, my good lord. KING CLAUDIUS Set me the stoops of wine upon that table. If Hamlet give the first or second hit, Or quit in answer of the third exchange, Let all the battlements their ordnance fire: The king shall drink to Hamlet's better breath; And in the cup an union shall he throw, Richer than that which four successive kings In Denmark's crown have worn. Give me the cups; And let the kettle to the trumpet speak, The trumpet to the cannoneer without, The cannons to the heavens, the heavens to earth, 'Now the king dunks to Hamlet.' Come, begin: And you, the judges, bear a wary eye. HAMLET Come on, sir. LAERTES Come, my lord. They play HAMLET One. LAERTES No. HAMLET Judgment. OSRIC A hit, a very palpable hit. LAERTES Well; again. KING CLAUDIUS Stay; give me drink. Hamlet, this pearl is thine; Here's to thy health. Trumpets sound, and cannon shot off within Give him the cup. HAMLET I'll play this bout first; set it by awhile. Come. They play Another hit; what say you? LAERTES A touch, a touch, I do confess. KING CLAUDIUS Our son shall win. QUEEN GERTRUDE He's fat, and scant of breath. Here, Hamlet, take my napkin, rub thy brows; The queen carouses to thy fortune, Hamlet. HAMLET Good madam! KING CLAUDIUS Gertrude, do not drink. QUEEN GERTRUDE I will, my lord; I pray you, pardon me. KING CLAUDIUS Aside It is the poison'd cup: it is too late. HAMLET I dare not drink yet, madam; by and by. QUEEN GERTRUDE Come, let me wipe thy face. LAERTES My lord, I'll hit him now. KING CLAUDIUS I do not think't. LAERTES Aside And yet 'tis almost 'gainst my conscience. HAMLET Come, for the third, Laertes: you but dally; I pray you, pass with your best violence; I am afeard you make a wanton of me. LAERTES Say you so? come on. They play OSRIC Nothing, neither way. LAERTES Have at you now! LAERTES wounds HAMLET; then in scuffling, they change rapiers, and HAMLET wounds LAERTES KING CLAUDIUS Part them; they are incensed. HAMLET Nay, come, again. QUEEN GERTRUDE falls OSRIC Look to the queen there, ho! HORATIO They bleed on both sides. How is it, my lord? OSRIC How is't, Laertes? LAERTES Why, as a woodcock to mine own springe, Osric; I am justly kill'd with mine own treachery. HAMLET How does the queen? KING CLAUDIUS She swounds to see them bleed. QUEEN GERTRUDE No, no, the drink, the drink,--O my dear Hamlet,-- The drink, the drink! I am poison'd. Dies HAMLET O villany! Ho! let the door be lock'd: Treachery! Seek it out. LAERTES It is here, Hamlet: Hamlet, thou art slain; No medicine in the world can do thee good; In thee there is not half an hour of life; The treacherous instrument is in thy hand, Unbated and envenom'd: the foul practise Hath turn'd itself on me lo, here I lie, Never to rise again: thy mother's poison'd: I can no more: the king, the king's to blame. HAMLET The point!--envenom'd too! Then, venom, to thy work. Stabs KING CLAUDIUS All Treason! treason! KING CLAUDIUS O, yet defend me, friends; I am but hurt. HAMLET Here, thou incestuous, murderous, damned Dane, Drink off this potion. Is thy union here? Follow my mother. KING CLAUDIUS dies LAERTES He is justly served; It is a poison temper'd by himself. Exchange forgiveness with me, noble Hamlet: Mine and my father's death come not upon thee, Nor thine on me. Dies HAMLET Heaven make thee free of it! I follow thee. I am dead, Horatio. Wretched queen, adieu! You that look pale and tremble at this chance, That are but mutes or audience to this act, Had I but time--as this fell sergeant, death, Is strict in his arrest--O, I could tell you-- But let it be. Horatio, I am dead; Thou livest; report me and my cause aright To the unsatisfied. HORATIO Never believe it: I am more an antique Roman than a Dane: Here's yet some liquor left. HAMLET As thou'rt a man, Give me the cup: let go; by heaven, I'll have't. O good Horatio, what a wounded name, Things standing thus unknown, shall live behind me! If thou didst ever hold me in thy heart Absent thee from felicity awhile, And in this harsh world draw thy breath in pain, To tell my story. March afar off, and shot within What warlike noise is this? OSRIC Young Fortinbras, with conquest come from Poland, To the ambassadors of England gives This warlike volley. HAMLET O, I die, Horatio; The potent poison quite o'er-crows my spirit: I cannot live to hear the news from England; But I do prophesy the election lights On Fortinbras: he has my dying voice; So tell him, with the occurrents, more and less, Which have solicited. The rest is silence. Dies HORATIO Now cracks a noble heart. Good night sweet prince: And flights of angels sing thee to thy rest! Why does the drum come hither? March within Enter FORTINBRAS, the English Ambassadors, and others PRINCE FORTINBRAS Where is this sight? HORATIO What is it ye would see? If aught of woe or wonder, cease your search. PRINCE FORTINBRAS This quarry cries on havoc. O proud death, What feast is toward in thine eternal cell, That thou so many princes at a shot So bloodily hast struck? First Ambassador The sight is dismal; And our affairs from England come too late: The ears are senseless that should give us hearing, To tell him his commandment is fulfill'd, That Rosencrantz and Guildenstern are dead: Where should we have our thanks? HORATIO Not from his mouth, Had it the ability of life to thank you: He never gave commandment for their death. But since, so jump upon this bloody question, You from the Polack wars, and you from England, Are here arrived give order that these bodies High on a stage be placed to the view; And let me speak to the yet unknowing world How these things came about: so shall you hear Of carnal, bloody, and unnatural acts, Of accidental judgments, casual slaughters, Of deaths put on by cunning and forced cause, And, in this upshot, purposes mistook Fall'n on the inventors' reads: all this can I Truly deliver. PRINCE FORTINBRAS Let us haste to hear it, And call the noblest to the audience. For me, with sorrow I embrace my fortune: I have some rights of memory in this kingdom, Which now to claim my vantage doth invite me. HORATIO Of that I shall have also cause to speak, And from his mouth whose voice will draw on more; But let this same be presently perform'd, Even while men's minds are wild; lest more mischance On plots and errors, happen. PRINCE FORTINBRAS Let four captains Bear Hamlet, like a soldier, to the stage; For he was likely, had he been put on, To have proved most royally: and, for his passage, The soldiers' music and the rites of war Speak loudly for him. Take up the bodies: such a sight as this Becomes the field, but here shows much amiss. Go, bid the soldiers shoot. A dead march. Exeunt, bearing off the dead bodies; after which a peal of ordnance is shot off
libxml-ruby-5.0.3/script/benchmark/parsecount0000644000004100000410000001635114620142101021356 0ustar www-datawww-data#!/usr/bin/env ruby # # Each test has an XML Parser open a 98k XML document and count one type of leaf # element (466 entries). This is repeated a total of 100 times, twice for each Parser. # Summary measurements are from the second test. # # Tests run on a MacBook Pro, Mac OS X 10.5.5, 4GB memory, 2.5 GHz Intel Core 2 Duo. # # Library versions: # hpricot 0.6.164 # libxml: 0.9.2 # # All benchmarks were run twice in sequence and the measurements presented here are from # the second run. Java automatically optimizes JRuby code which is run many times and the # speedup from the first to the second test is from 40 to 75%. There is no essential # difference in the speed of the C version of Ruby between the first test and the second. # # Summary: # # 100 times: Open 98k XML document and count one type of leaf element (466 entries) # # JRuby (Java 1.6.0_03-p3-Soylatte using server mode): jdom_document_builder 0.360 # MRI: libxml v0.9.2 0.383 # JRuby (Java 1.6.0_07): jdom_document_builder 0.401 # JRuby (Java 1.5.0_16): jdom_document_builder 0.428 # JRuby (Java 1.6.0_03-p3-Soylatte using server mode): hpricot 1.977 # JRuby (Java 1.5.0_16): hpricot 2.027 # JRuby (Java 1.6.0_07): hpricot 2.094 # MRI: hpricot 2.140 # JRuby (Java 1.6.0_03-p3-Soylatte using server mode): rexml 5.488 # JRuby (Java 1.5.0_16): rexml 5.569 # JRuby (Java 1.5.0_16): rexml 5.578 # MRI: rexml 8.606 # # Ruby version: MRI 1.8.6 (2008-03-03 rev 114), platform: universal-darwin9.0 # -------------------------------------------------------------------------------- # user system total real # rexml 8.170000 0.100000 8.270000 ( 8.606676) # hpricot 1.990000 0.040000 2.030000 ( 2.140865) # libxml 0.350000 0.020000 0.370000 ( 0.383475) # # JRuby 1.1.5 (svn r8078) on Java 1.5.0_16 # -------------------------------------------------------------------------------- # user system total real # rexml 5.578000 0.000000 5.578000 ( 5.578371) # hpricot 2.028000 0.000000 2.028000 ( 2.027348) # jdom_document_builder 0.429000 0.000000 0.429000 ( 0.428713) # # JRuby 1.1.5 (svn r8078) on Java 1.6.0_07 # -------------------------------------------------------------------------------- # user system total real # rexml 5.569000 0.000000 5.569000 ( 5.569135) # hpricot 2.094000 0.000000 2.094000 ( 2.093635) # jdom_document_builder 0.401000 0.000000 0.401000 ( 0.401115) # # JRuby 1.1.5 (svn r8078) on Java 1.6.0_07 using server mode (-J-server) # -------------------------------------------------------------------------------- # user system total real # rexml 5.489000 0.000000 5.489000 ( 5.488560) # hpricot 1.977000 0.000000 1.977000 ( 1.976845) # jdom_document_builder 0.377000 0.000000 0.377000 ( 0.377808) # # JRuby 1.1.5 (svn r8078) on Java 1.6.0_03-p3 (Soylatte) using server mode (-J-server) # -------------------------------------------------------------------------------- # user system total real # rexml 5.596000 0.000000 5.596000 ( 5.596212) # hpricot 1.937000 0.000000 1.937000 ( 1.937312) # jdom_document_builder 0.360000 0.000000 0.360000 ( 0.360068) require 'rubygems' require 'benchmark' require "rexml/document" require 'hpricot' if RUBY_PLATFORM =~ /java/ include Java import javax.xml.parsers.DocumentBuilder import javax.xml.parsers.DocumentBuilderFactory @dbf = DocumentBuilderFactory.new_instance @ruby_info = "Ruby version: JRuby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} rev #{RUBY_PATCHLEVEL}) [i386-jruby#{JRUBY_VERSION}]" @ruby_info << ", platform: Java, version #{java.lang.System.getProperty('java.version')}" else @ruby_info = "Ruby version: MRI #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} rev #{RUBY_PATCHLEVEL})" @ruby_info << ", platform: #{RUBY_PLATFORM}" gem 'nokogiri', '>= 1.0.6' require 'nokogiri' gem 'libxml-ruby', '>= 0.9.2' require 'libxml' @xml_parser = LibXML::XML::Parser.new end file = File.expand_path(File.join(File.dirname(__FILE__), "sock_entries.xml")) @bundle_with_466_sock_entries = File.read(file) def rexml_count_socks doc = REXML::Document.new(@bundle_with_466_sock_entries).root socks = doc.elements.to_a('./sockEntries').length end unless RUBY_PLATFORM =~ /java/ def nokogiri_count_socks #doc = Nokogiri(@bundle_with_466_sock_entries) #socks = doc.search('//sockEntries').length end def libxml_count_socks @xml_parser = LibXML::XML::Parser.new @xml_parser.string = @bundle_with_466_sock_entries doc = @xml_parser.parse socks = doc.find('//sockEntries').length end end def hpricot_count_socks doc = Hpricot.XML(@bundle_with_466_sock_entries) socks = doc.search("//sockEntries").length end if RUBY_PLATFORM =~ /java/ def jdom_document_builder_count_socks file = File.expand_path(File.join(File.dirname(__FILE__), "sock_entries.xml")) doc = @dbf.new_document_builder.parse(file).get_document_element socks = doc.getElementsByTagName("sockEntries") socks.get_length end end n = 100 test_iterations = ARGV.first.to_i test_iterations = 1 unless test_iterations > 1 puts puts @ruby_info puts puts "#{n} times: Open 98k XML document and count one type of leaf element (466 entries)" puts print "running benchmark " if test_iterations == 1 puts "once.\n\n" else puts "#{test_iterations} times.\n\n" end test_iterations.times do Benchmark.bmbm do |x| x.report("rexml") { n.times {rexml_count_socks} } x.report("hpricot") { n.times {hpricot_count_socks} } x.report("jdom_document_builder") { n.times {jdom_document_builder_count_socks} } if RUBY_PLATFORM =~ /java/ #x.report("nokogiri") { n.times {nokogiri_count_socks} } unless RUBY_PLATFORM =~ /java/ x.report("libxml") { n.times {libxml_count_socks} } unless RUBY_PLATFORM =~ /java/ end puts end # # jrexml doesn't appear to have any speedup in this test # # if RUBY_PLATFORM =~ /java/ # require 'jrexml' # def rexml_with_jrexml_count_socks # doc = REXML::Document.new(@bundle_with_466_sock_entries).root # socks = doc.elements.to_a('./sockEntries').length # end # # puts "\nNow add in JREXML to see if it speeds up rexml\n" # Benchmark.bmbm do |x| # x.report("rexml+jrexml") { n.times {rexml_with_jrexml_count_socks} } # end # puts # end