Make rexml library to the bundle gems

[Feature #16485][ruby-core:96683]
This commit is contained in:
Hiroshi SHIBATA 2020-01-11 21:37:00 +09:00 коммит произвёл SHIBATA Hiroshi
Родитель 012f297311
Коммит c3ccf23d58
160 изменённых файлов: 4 добавлений и 46104 удалений

Просмотреть файл

@ -239,10 +239,6 @@ Zachary Scott (zzak)
aycabta
https://github.com/ruby/reline
https://rubygems.org/gems/reline
[lib/rexml/*]
Kouhei Sutou (kou)
https://github.com/ruby/rexml
https://rubygems.org/gems/rexml
[lib/rss.rb, lib/rss/*]
Kouhei Sutou (kou)
https://github.com/ruby/rss
@ -357,3 +353,5 @@ Zachary Scott (zzak)
https://github.com/test-unit/test-unit
[xmlrpc]
https://github.com/ruby/xmlrpc
[rexml]
https://github.com/ruby/rexml

Просмотреть файл

@ -80,7 +80,6 @@ Prime:: Prime numbers and factorization library
PStore:: Implements a file based persistence mechanism based on a Hash
Racc:: A LALR(1) parser generator written in Ruby.
RDoc:: Produces HTML and command-line documentation for Ruby
REXML:: An XML toolkit for Ruby
RSS:: Family of libraries that support various formats of XML "feeds"
Singleton:: Implementation of the Singleton pattern for Ruby
Timeout:: Auto-terminate potentially long-running operations in Ruby
@ -119,3 +118,4 @@ PowerAssert:: Power Assert for Ruby.
Rake:: Ruby build program with capabilities similar to make
Test::Unit:: A compatibility layer for MiniTest
XMLRPC:: Remote Procedure Call over HTTP support for Ruby
REXML:: An XML toolkit for Ruby

Просмотреть файл

@ -4,3 +4,4 @@ power_assert 1.1.5 https://github.com/k-tsj/power_assert
rake 13.0.1 https://github.com/ruby/rake
test-unit 3.3.4 https://github.com/test-unit/test-unit
xmlrpc 0.3.0 https://github.com/ruby/xmlrpc
rexml 3.2.3 https://github.com/ruby/rexml

Просмотреть файл

@ -1,63 +0,0 @@
# frozen_string_literal: false
#vim:ts=2 sw=2 noexpandtab:
require_relative 'child'
require_relative 'source'
module REXML
# This class needs:
# * Documentation
# * Work! Not all types of attlists are intelligently parsed, so we just
# spew back out what we get in. This works, but it would be better if
# we formatted the output ourselves.
#
# AttlistDecls provide *just* enough support to allow namespace
# declarations. If you need some sort of generalized support, or have an
# interesting idea about how to map the hideous, terrible design of DTD
# AttlistDecls onto an intuitive Ruby interface, let me know. I'm desperate
# for anything to make DTDs more palateable.
class AttlistDecl < Child
include Enumerable
# What is this? Got me.
attr_reader :element_name
# Create an AttlistDecl, pulling the information from a Source. Notice
# that this isn't very convenient; to create an AttlistDecl, you basically
# have to format it yourself, and then have the initializer parse it.
# Sorry, but for the foreseeable future, DTD support in REXML is pretty
# weak on convenience. Have I mentioned how much I hate DTDs?
def initialize(source)
super()
if (source.kind_of? Array)
@element_name, @pairs, @contents = *source
end
end
# Access the attlist attribute/value pairs.
# value = attlist_decl[ attribute_name ]
def [](key)
@pairs[key]
end
# Whether an attlist declaration includes the given attribute definition
# if attlist_decl.include? "xmlns:foobar"
def include?(key)
@pairs.keys.include? key
end
# Iterate over the key/value pairs:
# attlist_decl.each { |attribute_name, attribute_value| ... }
def each(&block)
@pairs.each(&block)
end
# Write out exactly what we got in.
def write out, indent=-1
out << @contents
end
def node_type
:attlistdecl
end
end
end

Просмотреть файл

@ -1,205 +0,0 @@
# frozen_string_literal: false
require_relative "namespace"
require_relative 'text'
module REXML
# Defines an Element Attribute; IE, a attribute=value pair, as in:
# <element attribute="value"/>. Attributes can be in their own
# namespaces. General users of REXML will not interact with the
# Attribute class much.
class Attribute
include Node
include Namespace
# The element to which this attribute belongs
attr_reader :element
# The normalized value of this attribute. That is, the attribute with
# entities intact.
attr_writer :normalized
PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
# Constructor.
# FIXME: The parser doesn't catch illegal characters in attributes
#
# first::
# Either: an Attribute, which this new attribute will become a
# clone of; or a String, which is the name of this attribute
# second::
# If +first+ is an Attribute, then this may be an Element, or nil.
# If nil, then the Element parent of this attribute is the parent
# of the +first+ Attribute. If the first argument is a String,
# then this must also be a String, and is the content of the attribute.
# If this is the content, it must be fully normalized (contain no
# illegal characters).
# parent::
# Ignored unless +first+ is a String; otherwise, may be the Element
# parent of this attribute, or nil.
#
#
# Attribute.new( attribute_to_clone )
# Attribute.new( attribute_to_clone, parent_element )
# Attribute.new( "attr", "attr_value" )
# Attribute.new( "attr", "attr_value", parent_element )
def initialize( first, second=nil, parent=nil )
@normalized = @unnormalized = @element = nil
if first.kind_of? Attribute
self.name = first.expanded_name
@unnormalized = first.value
if second.kind_of? Element
@element = second
else
@element = first.element
end
elsif first.kind_of? String
@element = parent
self.name = first
@normalized = second.to_s
else
raise "illegal argument #{first.class.name} to Attribute constructor"
end
end
# Returns the namespace of the attribute.
#
# e = Element.new( "elns:myelement" )
# e.add_attribute( "nsa:a", "aval" )
# e.add_attribute( "b", "bval" )
# e.attributes.get_attribute( "a" ).prefix # -> "nsa"
# e.attributes.get_attribute( "b" ).prefix # -> ""
# a = Attribute.new( "x", "y" )
# a.prefix # -> ""
def prefix
super
end
# Returns the namespace URL, if defined, or nil otherwise
#
# e = Element.new("el")
# e.add_namespace("ns", "http://url")
# e.add_attribute("ns:a", "b")
# e.add_attribute("nsx:a", "c")
# e.attribute("ns:a").namespace # => "http://url"
# e.attribute("nsx:a").namespace # => nil
#
# This method always returns "" for no namespace attribute. Because
# the default namespace doesn't apply to attribute names.
#
# From https://www.w3.org/TR/xml-names/#uniqAttrs
#
# > the default namespace does not apply to attribute names
#
# e = REXML::Element.new("el")
# e.add_namespace("", "http://example.com/")
# e.namespace # => "http://example.com/"
# e.add_attribute("a", "b")
# e.attribute("a").namespace # => ""
def namespace arg=nil
arg = prefix if arg.nil?
if arg == ""
""
else
@element.namespace(arg)
end
end
# Returns true if other is an Attribute and has the same name and value,
# false otherwise.
def ==( other )
other.kind_of?(Attribute) and other.name==name and other.value==value
end
# Creates (and returns) a hash from both the name and value
def hash
name.hash + value.hash
end
# Returns this attribute out as XML source, expanding the name
#
# a = Attribute.new( "x", "y" )
# a.to_string # -> "x='y'"
# b = Attribute.new( "ns:x", "y" )
# b.to_string # -> "ns:x='y'"
def to_string
if @element and @element.context and @element.context[:attribute_quote] == :quote
%Q^#@expanded_name="#{to_s().gsub(/"/, '&quot;')}"^
else
"#@expanded_name='#{to_s().gsub(/'/, '&apos;')}'"
end
end
def doctype
if @element
doc = @element.document
doc.doctype if doc
end
end
# Returns the attribute value, with entities replaced
def to_s
return @normalized if @normalized
@normalized = Text::normalize( @unnormalized, doctype )
@unnormalized = nil
@normalized
end
# Returns the UNNORMALIZED value of this attribute. That is, entities
# have been expanded to their values
def value
return @unnormalized if @unnormalized
@unnormalized = Text::unnormalize( @normalized, doctype )
@normalized = nil
@unnormalized
end
# Returns a copy of this attribute
def clone
Attribute.new self
end
# Sets the element of which this object is an attribute. Normally, this
# is not directly called.
#
# Returns this attribute
def element=( element )
@element = element
if @normalized
Text.check( @normalized, NEEDS_A_SECOND_CHECK, doctype )
end
self
end
# Removes this Attribute from the tree, and returns true if successful
#
# This method is usually not called directly.
def remove
@element.attributes.delete self.name unless @element.nil?
end
# Writes this attribute (EG, puts 'key="value"' to the output)
def write( output, indent=-1 )
output << to_string
end
def node_type
:attribute
end
def inspect
rv = ""
write( rv )
rv
end
def xpath
path = @element.xpath
path += "/@#{self.expanded_name}"
return path
end
end
end
#vim:ts=2 sw=2 noexpandtab:

Просмотреть файл

@ -1,68 +0,0 @@
# frozen_string_literal: false
require_relative "text"
module REXML
class CData < Text
START = '<![CDATA['
STOP = ']]>'
ILLEGAL = /(\]\]>)/
# Constructor. CData is data between <![CDATA[ ... ]]>
#
# _Examples_
# CData.new( source )
# CData.new( "Here is some CDATA" )
# CData.new( "Some unprocessed data", respect_whitespace_TF, parent_element )
def initialize( first, whitespace=true, parent=nil )
super( first, whitespace, parent, false, true, ILLEGAL )
end
# Make a copy of this object
#
# _Examples_
# c = CData.new( "Some text" )
# d = c.clone
# d.to_s # -> "Some text"
def clone
CData.new self
end
# Returns the content of this CData object
#
# _Examples_
# c = CData.new( "Some text" )
# c.to_s # -> "Some text"
def to_s
@string
end
def value
@string
end
# == DEPRECATED
# See the rexml/formatters package
#
# Generates XML output of this object
#
# output::
# Where to write the string. Defaults to $stdout
# indent::
# The amount to indent this node by
# transitive::
# Ignored
# ie_hack::
# Ignored
#
# _Examples_
# c = CData.new( " Some text " )
# c.write( $stdout ) #-> <![CDATA[ Some text ]]>
def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
Kernel.warn( "#{self.class.name}.write is deprecated", uplevel: 1)
indent( output, indent )
output << START
output << @string
output << STOP
end
end
end

Просмотреть файл

@ -1,97 +0,0 @@
# frozen_string_literal: false
require_relative "node"
module REXML
##
# A Child object is something contained by a parent, and this class
# contains methods to support that. Most user code will not use this
# class directly.
class Child
include Node
attr_reader :parent # The Parent of this object
# Constructor. Any inheritors of this class should call super to make
# sure this method is called.
# parent::
# if supplied, the parent of this child will be set to the
# supplied value, and self will be added to the parent
def initialize( parent = nil )
@parent = nil
# Declare @parent, but don't define it. The next line sets the
# parent.
parent.add( self ) if parent
end
# Replaces this object with another object. Basically, calls
# Parent.replace_child
#
# Returns:: self
def replace_with( child )
@parent.replace_child( self, child )
self
end
# Removes this child from the parent.
#
# Returns:: self
def remove
unless @parent.nil?
@parent.delete self
end
self
end
# Sets the parent of this child to the supplied argument.
#
# other::
# Must be a Parent object. If this object is the same object as the
# existing parent of this child, no action is taken. Otherwise, this
# child is removed from the current parent (if one exists), and is added
# to the new parent.
# Returns:: The parent added
def parent=( other )
return @parent if @parent == other
@parent.delete self if defined? @parent and @parent
@parent = other
end
alias :next_sibling :next_sibling_node
alias :previous_sibling :previous_sibling_node
# Sets the next sibling of this child. This can be used to insert a child
# after some other child.
# a = Element.new("a")
# b = a.add_element("b")
# c = Element.new("c")
# b.next_sibling = c
# # => <a><b/><c/></a>
def next_sibling=( other )
parent.insert_after self, other
end
# Sets the previous sibling of this child. This can be used to insert a
# child before some other child.
# a = Element.new("a")
# b = a.add_element("b")
# c = Element.new("c")
# b.previous_sibling = c
# # => <a><b/><c/></a>
def previous_sibling=(other)
parent.insert_before self, other
end
# Returns:: the document this child belongs to, or nil if this child
# belongs to no document
def document
return parent.document unless parent.nil?
nil
end
# This doesn't yet handle encodings
def bytes
document.encoding
to_s
end
end
end

Просмотреть файл

@ -1,80 +0,0 @@
# frozen_string_literal: false
require_relative "child"
module REXML
##
# Represents an XML comment; that is, text between \<!-- ... -->
class Comment < Child
include Comparable
START = "<!--"
STOP = "-->"
# The content text
attr_accessor :string
##
# Constructor. The first argument can be one of three types:
# @param first If String, the contents of this comment are set to the
# argument. If Comment, the argument is duplicated. If
# Source, the argument is scanned for a comment.
# @param second If the first argument is a Source, this argument
# should be nil, not supplied, or a Parent to be set as the parent
# of this object
def initialize( first, second = nil )
super(second)
if first.kind_of? String
@string = first
elsif first.kind_of? Comment
@string = first.string
end
end
def clone
Comment.new self
end
# == DEPRECATED
# See REXML::Formatters
#
# output::
# Where to write the string
# indent::
# An integer. If -1, no indenting will be used; otherwise, the
# indentation will be this number of spaces, and children will be
# indented an additional amount.
# transitive::
# Ignored by this class. The contents of comments are never modified.
# ie_hack::
# Needed for conformity to the child API, but not used by this class.
def write( output, indent=-1, transitive=false, ie_hack=false )
Kernel.warn("Comment.write is deprecated. See REXML::Formatters", uplevel: 1)
indent( output, indent )
output << START
output << @string
output << STOP
end
alias :to_s :string
##
# Compares this Comment to another; the contents of the comment are used
# in the comparison.
def <=>(other)
other.to_s <=> @string
end
##
# Compares this Comment to another; the contents of the comment are used
# in the comparison.
def ==( other )
other.kind_of? Comment and
(other <=> self) == 0
end
def node_type
:comment
end
end
end
#vim:ts=2 sw=2 noexpandtab:

Просмотреть файл

@ -1,287 +0,0 @@
# frozen_string_literal: false
require_relative "parent"
require_relative "parseexception"
require_relative "namespace"
require_relative 'entity'
require_relative 'attlistdecl'
require_relative 'xmltokens'
module REXML
# Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
# ... >. DOCTYPES can be used to declare the DTD of a document, as well as
# being used to declare entities used in the document.
class DocType < Parent
include XMLTokens
START = "<!DOCTYPE"
STOP = ">"
SYSTEM = "SYSTEM"
PUBLIC = "PUBLIC"
DEFAULT_ENTITIES = {
'gt'=>EntityConst::GT,
'lt'=>EntityConst::LT,
'quot'=>EntityConst::QUOT,
"apos"=>EntityConst::APOS
}
# name is the name of the doctype
# external_id is the referenced DTD, if given
attr_reader :name, :external_id, :entities, :namespaces
# Constructor
#
# dt = DocType.new( 'foo', '-//I/Hate/External/IDs' )
# # <!DOCTYPE foo '-//I/Hate/External/IDs'>
# dt = DocType.new( doctype_to_clone )
# # Incomplete. Shallow clone of doctype
#
# +Note+ that the constructor:
#
# Doctype.new( Source.new( "<!DOCTYPE foo 'bar'>" ) )
#
# is _deprecated_. Do not use it. It will probably disappear.
def initialize( first, parent=nil )
@entities = DEFAULT_ENTITIES
@long_name = @uri = nil
if first.kind_of? String
super()
@name = first
@external_id = parent
elsif first.kind_of? DocType
super( parent )
@name = first.name
@external_id = first.external_id
elsif first.kind_of? Array
super( parent )
@name = first[0]
@external_id = first[1]
@long_name = first[2]
@uri = first[3]
elsif first.kind_of? Source
super( parent )
parser = Parsers::BaseParser.new( first )
event = parser.pull
if event[0] == :start_doctype
@name, @external_id, @long_name, @uri, = event[1..-1]
end
else
super()
end
end
def node_type
:doctype
end
def attributes_of element
rv = []
each do |child|
child.each do |key,val|
rv << Attribute.new(key,val)
end if child.kind_of? AttlistDecl and child.element_name == element
end
rv
end
def attribute_of element, attribute
att_decl = find do |child|
child.kind_of? AttlistDecl and
child.element_name == element and
child.include? attribute
end
return nil unless att_decl
att_decl[attribute]
end
def clone
DocType.new self
end
# output::
# Where to write the string
# indent::
# An integer. If -1, no indentation will be used; otherwise, the
# indentation will be this number of spaces, and children will be
# indented an additional amount.
# transitive::
# Ignored
# ie_hack::
# Ignored
def write( output, indent=0, transitive=false, ie_hack=false )
f = REXML::Formatters::Default.new
c = context
if c and c[:prologue_quote] == :apostrophe
quote = "'"
else
quote = "\""
end
indent( output, indent )
output << START
output << ' '
output << @name
output << " #{@external_id}" if @external_id
output << " #{quote}#{@long_name}#{quote}" if @long_name
output << " #{quote}#{@uri}#{quote}" if @uri
unless @children.empty?
output << ' ['
@children.each { |child|
output << "\n"
f.write( child, output )
}
output << "\n]"
end
output << STOP
end
def context
if @parent
@parent.context
else
nil
end
end
def entity( name )
@entities[name].unnormalized if @entities[name]
end
def add child
super(child)
@entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES
@entities[ child.name ] = child if child.kind_of? Entity
end
# This method retrieves the public identifier identifying the document's
# DTD.
#
# Method contributed by Henrik Martensson
def public
case @external_id
when "SYSTEM"
nil
when "PUBLIC"
strip_quotes(@long_name)
end
end
# This method retrieves the system identifier identifying the document's DTD
#
# Method contributed by Henrik Martensson
def system
case @external_id
when "SYSTEM"
strip_quotes(@long_name)
when "PUBLIC"
@uri.kind_of?(String) ? strip_quotes(@uri) : nil
end
end
# This method returns a list of notations that have been declared in the
# _internal_ DTD subset. Notations in the external DTD subset are not
# listed.
#
# Method contributed by Henrik Martensson
def notations
children().select {|node| node.kind_of?(REXML::NotationDecl)}
end
# Retrieves a named notation. Only notations declared in the internal
# DTD subset can be retrieved.
#
# Method contributed by Henrik Martensson
def notation(name)
notations.find { |notation_decl|
notation_decl.name == name
}
end
private
# Method contributed by Henrik Martensson
def strip_quotes(quoted_string)
quoted_string =~ /^[\'\"].*[\'\"]$/ ?
quoted_string[1, quoted_string.length-2] :
quoted_string
end
end
# We don't really handle any of these since we're not a validating
# parser, so we can be pretty dumb about them. All we need to be able
# to do is spew them back out on a write()
# This is an abstract class. You never use this directly; it serves as a
# parent class for the specific declarations.
class Declaration < Child
def initialize src
super()
@string = src
end
def to_s
@string+'>'
end
# == DEPRECATED
# See REXML::Formatters
#
def write( output, indent )
output << to_s
end
end
public
class ElementDecl < Declaration
def initialize( src )
super
end
end
class ExternalEntity < Child
def initialize( src )
super()
@entity = src
end
def to_s
@entity
end
def write( output, indent )
output << @entity
end
end
class NotationDecl < Child
attr_accessor :public, :system
def initialize name, middle, pub, sys
super(nil)
@name = name
@middle = middle
@public = pub
@system = sys
end
def to_s
c = nil
c = parent.context if parent
if c and c[:prologue_quote] == :apostrophe
quote = "'"
else
quote = "\""
end
notation = "<!NOTATION #{@name} #{@middle}"
notation << " #{quote}#{@public}#{quote}" if @public
notation << " #{quote}#{@system}#{quote}" if @system
notation << ">"
notation
end
def write( output, indent=-1 )
output << to_s
end
# This method retrieves the name of the notation.
#
# Method contributed by Henrik Martensson
def name
@name
end
end
end

Просмотреть файл

@ -1,291 +0,0 @@
# frozen_string_literal: false
require_relative "security"
require_relative "element"
require_relative "xmldecl"
require_relative "source"
require_relative "comment"
require_relative "doctype"
require_relative "instruction"
require_relative "rexml"
require_relative "parseexception"
require_relative "output"
require_relative "parsers/baseparser"
require_relative "parsers/streamparser"
require_relative "parsers/treeparser"
module REXML
# Represents a full XML document, including PIs, a doctype, etc. A
# Document has a single child that can be accessed by root().
# Note that if you want to have an XML declaration written for a document
# you create, you must add one; REXML documents do not write a default
# declaration for you. See |DECLARATION| and |write|.
class Document < Element
# A convenient default XML declaration. If you want an XML declaration,
# the easiest way to add one is mydoc << Document::DECLARATION
# +DEPRECATED+
# Use: mydoc << XMLDecl.default
DECLARATION = XMLDecl.default
# Constructor
# @param source if supplied, must be a Document, String, or IO.
# Documents have their context and Element attributes cloned.
# Strings are expected to be valid XML documents. IOs are expected
# to be sources of valid XML documents.
# @param context if supplied, contains the context of the document;
# this should be a Hash.
def initialize( source = nil, context = {} )
@entity_expansion_count = 0
super()
@context = context
return if source.nil?
if source.kind_of? Document
@context = source.context
super source
else
build( source )
end
end
def node_type
:document
end
# Should be obvious
def clone
Document.new self
end
# According to the XML spec, a root node has no expanded name
def expanded_name
''
#d = doc_type
#d ? d.name : "UNDEFINED"
end
alias :name :expanded_name
# We override this, because XMLDecls and DocTypes must go at the start
# of the document
def add( child )
if child.kind_of? XMLDecl
if @children[0].kind_of? XMLDecl
@children[0] = child
else
@children.unshift child
end
child.parent = self
elsif child.kind_of? DocType
# Find first Element or DocType node and insert the decl right
# before it. If there is no such node, just insert the child at the
# end. If there is a child and it is an DocType, then replace it.
insert_before_index = @children.find_index { |x|
x.kind_of?(Element) || x.kind_of?(DocType)
}
if insert_before_index # Not null = not end of list
if @children[ insert_before_index ].kind_of? DocType
@children[ insert_before_index ] = child
else
@children[ insert_before_index-1, 0 ] = child
end
else # Insert at end of list
@children << child
end
child.parent = self
else
rv = super
raise "attempted adding second root element to document" if @elements.size > 1
rv
end
end
alias :<< :add
def add_element(arg=nil, arg2=nil)
rv = super
raise "attempted adding second root element to document" if @elements.size > 1
rv
end
# @return the root Element of the document, or nil if this document
# has no children.
def root
elements[1]
#self
#@children.find { |item| item.kind_of? Element }
end
# @return the DocType child of the document, if one exists,
# and nil otherwise.
def doctype
@children.find { |item| item.kind_of? DocType }
end
# @return the XMLDecl of this document; if no XMLDecl has been
# set, the default declaration is returned.
def xml_decl
rv = @children[0]
return rv if rv.kind_of? XMLDecl
@children.unshift(XMLDecl.default)[0]
end
# @return the XMLDecl version of this document as a String.
# If no XMLDecl has been set, returns the default version.
def version
xml_decl().version
end
# @return the XMLDecl encoding of this document as an
# Encoding object.
# If no XMLDecl has been set, returns the default encoding.
def encoding
xml_decl().encoding
end
# @return the XMLDecl standalone value of this document as a String.
# If no XMLDecl has been set, returns the default setting.
def stand_alone?
xml_decl().stand_alone?
end
# :call-seq:
# doc.write(output=$stdout, indent=-1, transtive=false, ie_hack=false, encoding=nil)
# doc.write(options={:output => $stdout, :indent => -1, :transtive => false, :ie_hack => false, :encoding => nil})
#
# Write the XML tree out, optionally with indent. This writes out the
# entire XML document, including XML declarations, doctype declarations,
# and processing instructions (if any are given).
#
# A controversial point is whether Document should always write the XML
# declaration (<?xml version='1.0'?>) whether or not one is given by the
# user (or source document). REXML does not write one if one was not
# specified, because it adds unnecessary bandwidth to applications such
# as XML-RPC.
#
# Accept Nth argument style and options Hash style as argument.
# The recommended style is options Hash style for one or more
# arguments case.
#
# _Examples_
# Document.new("<a><b/></a>").write
#
# output = ""
# Document.new("<a><b/></a>").write(output)
#
# output = ""
# Document.new("<a><b/></a>").write(:output => output, :indent => 2)
#
# See also the classes in the rexml/formatters package for the proper way
# to change the default formatting of XML output.
#
# _Examples_
#
# output = ""
# tr = Transitive.new
# tr.write(Document.new("<a><b/></a>"), output)
#
# output::
# output an object which supports '<< string'; this is where the
# document will be written.
# indent::
# An integer. If -1, no indenting will be used; otherwise, the
# indentation will be twice this number of spaces, and children will be
# indented an additional amount. For a value of 3, every item will be
# indented 3 more levels, or 6 more spaces (2 * 3). Defaults to -1
# transitive::
# If transitive is true and indent is >= 0, then the output will be
# pretty-printed in such a way that the added whitespace does not affect
# the absolute *value* of the document -- that is, it leaves the value
# and number of Text nodes in the document unchanged.
# ie_hack::
# This hack inserts a space before the /> on empty tags to address
# a limitation of Internet Explorer. Defaults to false
# encoding::
# Encoding name as String. Change output encoding to specified encoding
# instead of encoding in XML declaration.
# Defaults to nil. It means encoding in XML declaration is used.
def write(*arguments)
if arguments.size == 1 and arguments[0].class == Hash
options = arguments[0]
output = options[:output]
indent = options[:indent]
transitive = options[:transitive]
ie_hack = options[:ie_hack]
encoding = options[:encoding]
else
output, indent, transitive, ie_hack, encoding, = *arguments
end
output ||= $stdout
indent ||= -1
transitive = false if transitive.nil?
ie_hack = false if ie_hack.nil?
encoding ||= xml_decl.encoding
if encoding != 'UTF-8' && !output.kind_of?(Output)
output = Output.new( output, encoding )
end
formatter = if indent > -1
if transitive
require_relative "formatters/transitive"
REXML::Formatters::Transitive.new( indent, ie_hack )
else
REXML::Formatters::Pretty.new( indent, ie_hack )
end
else
REXML::Formatters::Default.new( ie_hack )
end
formatter.write( self, output )
end
def Document::parse_stream( source, listener )
Parsers::StreamParser.new( source, listener ).parse
end
# Set the entity expansion limit. By default the limit is set to 10000.
#
# Deprecated. Use REXML::Security.entity_expansion_limit= instead.
def Document::entity_expansion_limit=( val )
Security.entity_expansion_limit = val
end
# Get the entity expansion limit. By default the limit is set to 10000.
#
# Deprecated. Use REXML::Security.entity_expansion_limit= instead.
def Document::entity_expansion_limit
return Security.entity_expansion_limit
end
# Set the entity expansion limit. By default the limit is set to 10240.
#
# Deprecated. Use REXML::Security.entity_expansion_text_limit= instead.
def Document::entity_expansion_text_limit=( val )
Security.entity_expansion_text_limit = val
end
# Get the entity expansion limit. By default the limit is set to 10240.
#
# Deprecated. Use REXML::Security.entity_expansion_text_limit instead.
def Document::entity_expansion_text_limit
return Security.entity_expansion_text_limit
end
attr_reader :entity_expansion_count
def record_entity_expansion
@entity_expansion_count += 1
if @entity_expansion_count > Security.entity_expansion_limit
raise "number of entity expansions exceeded, processing aborted."
end
end
def document
self
end
private
def build( source )
Parsers::TreeParser.new( source, self ).parse
end
end
end

Просмотреть файл

@ -1,11 +0,0 @@
# frozen_string_literal: false
require_relative "../child"
module REXML
module DTD
class AttlistDecl < Child
START = "<!ATTLIST"
START_RE = /^\s*#{START}/um
PATTERN_RE = /\s*(#{START}.*?>)/um
end
end
end

Просмотреть файл

@ -1,47 +0,0 @@
# frozen_string_literal: false
require_relative "elementdecl"
require_relative "entitydecl"
require_relative "../comment"
require_relative "notationdecl"
require_relative "attlistdecl"
require_relative "../parent"
module REXML
module DTD
class Parser
def Parser.parse( input )
case input
when String
parse_helper input
when File
parse_helper input.read
end
end
# Takes a String and parses it out
def Parser.parse_helper( input )
contents = Parent.new
while input.size > 0
case input
when ElementDecl.PATTERN_RE
match = $&
contents << ElementDecl.new( match )
when AttlistDecl.PATTERN_RE
matchdata = $~
contents << AttlistDecl.new( matchdata )
when EntityDecl.PATTERN_RE
matchdata = $~
contents << EntityDecl.new( matchdata )
when Comment.PATTERN_RE
matchdata = $~
contents << Comment.new( matchdata )
when NotationDecl.PATTERN_RE
matchdata = $~
contents << NotationDecl.new( matchdata )
end
end
contents
end
end
end
end

Просмотреть файл

@ -1,18 +0,0 @@
# frozen_string_literal: false
require_relative "../child"
module REXML
module DTD
class ElementDecl < Child
START = "<!ELEMENT"
START_RE = /^\s*#{START}/um
# PATTERN_RE = /^\s*(#{START}.*?)>/um
PATTERN_RE = /^\s*#{START}\s+((?:[:\w][-\.\w]*:)?[-!\*\.\w]*)(.*?)>/
#\s*((((["']).*?\5)|[^\/'">]*)*?)(\/)?>/um, true)
def initialize match
@name = match[1]
@rest = match[2]
end
end
end
end

Просмотреть файл

@ -1,57 +0,0 @@
# frozen_string_literal: false
require_relative "../child"
module REXML
module DTD
class EntityDecl < Child
START = "<!ENTITY"
START_RE = /^\s*#{START}/um
PUBLIC = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+PUBLIC\s+((["']).*?\3)\s+((["']).*?\5)\s*>/um
SYSTEM = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+SYSTEM\s+((["']).*?\3)(?:\s+NDATA\s+\w+)?\s*>/um
PLAIN = /^\s*#{START}\s+(\w+)\s+((["']).*?\3)\s*>/um
PERCENT = /^\s*#{START}\s+%\s+(\w+)\s+((["']).*?\3)\s*>/um
# <!ENTITY name SYSTEM "...">
# <!ENTITY name "...">
def initialize src
super()
md = nil
if src.match( PUBLIC )
md = src.match( PUBLIC, true )
@middle = "PUBLIC"
@content = "#{md[2]} #{md[4]}"
elsif src.match( SYSTEM )
md = src.match( SYSTEM, true )
@middle = "SYSTEM"
@content = md[2]
elsif src.match( PLAIN )
md = src.match( PLAIN, true )
@middle = ""
@content = md[2]
elsif src.match( PERCENT )
md = src.match( PERCENT, true )
@middle = ""
@content = md[2]
end
raise ParseException.new("failed Entity match", src) if md.nil?
@name = md[1]
end
def to_s
rv = "<!ENTITY #@name "
rv << "#@middle " if @middle.size > 0
rv << @content
rv
end
def write( output, indent )
indent( output, indent )
output << to_s
end
def EntityDecl.parse_source source, listener
md = source.match( PATTERN_RE, true )
thing = md[0].squeeze(" \t\n\r")
listener.send inspect.downcase, thing
end
end
end
end

Просмотреть файл

@ -1,40 +0,0 @@
# frozen_string_literal: false
require_relative "../child"
module REXML
module DTD
class NotationDecl < Child
START = "<!NOTATION"
START_RE = /^\s*#{START}/um
PUBLIC = /^\s*#{START}\s+(\w[\w-]*)\s+(PUBLIC)\s+((["']).*?\4)\s*>/um
SYSTEM = /^\s*#{START}\s+(\w[\w-]*)\s+(SYSTEM)\s+((["']).*?\4)\s*>/um
def initialize src
super()
if src.match( PUBLIC )
md = src.match( PUBLIC, true )
elsif src.match( SYSTEM )
md = src.match( SYSTEM, true )
else
raise ParseException.new( "error parsing notation: no matching pattern", src )
end
@name = md[1]
@middle = md[2]
@rest = md[3]
end
def to_s
"<!NOTATION #@name #@middle #@rest>"
end
def write( output, indent )
indent( output, indent )
output << to_s
end
def NotationDecl.parse_source source, listener
md = source.match( PATTERN_RE, true )
thing = md[0].squeeze(" \t\n\r")
listener.send inspect.downcase, thing
end
end
end
end

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,51 +0,0 @@
# coding: US-ASCII
# frozen_string_literal: false
module REXML
module Encoding
# ID ---> Encoding name
attr_reader :encoding
def encoding=(encoding)
encoding = encoding.name if encoding.is_a?(Encoding)
if encoding.is_a?(String)
original_encoding = encoding
encoding = find_encoding(encoding)
unless encoding
raise ArgumentError, "Bad encoding name #{original_encoding}"
end
end
return false if defined?(@encoding) and encoding == @encoding
if encoding
@encoding = encoding.upcase
else
@encoding = 'UTF-8'
end
true
end
def encode(string)
string.encode(@encoding)
end
def decode(string)
string.encode(::Encoding::UTF_8, @encoding)
end
private
def find_encoding(name)
case name
when /\Ashift-jis\z/i
return "SHIFT_JIS"
when /\ACP-(\d+)\z/
name = "CP#{$1}"
when /\AUTF-8\z/i
return name
end
begin
::Encoding::Converter.search_convpath(name, 'UTF-8')
rescue ::Encoding::ConverterNotFoundError
return nil
end
name
end
end
end

Просмотреть файл

@ -1,171 +0,0 @@
# frozen_string_literal: false
require_relative 'child'
require_relative 'source'
require_relative 'xmltokens'
module REXML
class Entity < Child
include XMLTokens
PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#"
SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))}
PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')}
EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
NDATADECL = "\\s+NDATA\\s+#{NAME}"
PEREFERENCE = "%#{NAME};"
ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
PEDECL = "<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
attr_reader :name, :external, :ref, :ndata, :pubid
# Create a new entity. Simple entities can be constructed by passing a
# name, value to the constructor; this creates a generic, plain entity
# reference. For anything more complicated, you have to pass a Source to
# the constructor with the entity definition, or use the accessor methods.
# +WARNING+: There is no validation of entity state except when the entity
# is read from a stream. If you start poking around with the accessors,
# you can easily create a non-conformant Entity.
#
# e = Entity.new( 'amp', '&' )
def initialize stream, value=nil, parent=nil, reference=false
super(parent)
@ndata = @pubid = @value = @external = nil
if stream.kind_of? Array
@name = stream[1]
if stream[-1] == '%'
@reference = true
stream.pop
else
@reference = false
end
if stream[2] =~ /SYSTEM|PUBLIC/
@external = stream[2]
if @external == 'SYSTEM'
@ref = stream[3]
@ndata = stream[4] if stream.size == 5
else
@pubid = stream[3]
@ref = stream[4]
end
else
@value = stream[2]
end
else
@reference = reference
@external = nil
@name = stream
@value = value
end
end
# Evaluates whether the given string matches an entity definition,
# returning true if so, and false otherwise.
def Entity::matches? string
(ENTITYDECL =~ string) == 0
end
# Evaluates to the unnormalized value of this entity; that is, replacing
# all entities -- both %ent; and &ent; entities. This differs from
# +value()+ in that +value+ only replaces %ent; entities.
def unnormalized
document.record_entity_expansion unless document.nil?
v = value()
return nil if v.nil?
@unnormalized = Text::unnormalize(v, parent)
@unnormalized
end
#once :unnormalized
# Returns the value of this entity unprocessed -- raw. This is the
# normalized value; that is, with all %ent; and &ent; entities intact
def normalized
@value
end
# Write out a fully formed, correct entity definition (assuming the Entity
# object itself is valid.)
#
# out::
# An object implementing <TT>&lt;&lt;</TT> to which the entity will be
# output
# indent::
# *DEPRECATED* and ignored
def write out, indent=-1
out << '<!ENTITY '
out << '% ' if @reference
out << @name
out << ' '
if @external
out << @external << ' '
if @pubid
q = @pubid.include?('"')?"'":'"'
out << q << @pubid << q << ' '
end
q = @ref.include?('"')?"'":'"'
out << q << @ref << q
out << ' NDATA ' << @ndata if @ndata
else
q = @value.include?('"')?"'":'"'
out << q << @value << q
end
out << '>'
end
# Returns this entity as a string. See write().
def to_s
rv = ''
write rv
rv
end
PEREFERENCE_RE = /#{PEREFERENCE}/um
# Returns the value of this entity. At the moment, only internal entities
# are processed. If the value contains internal references (IE,
# %blah;), those are replaced with their values. IE, if the doctype
# contains:
# <!ENTITY % foo "bar">
# <!ENTITY yada "nanoo %foo; nanoo>
# then:
# doctype.entity('yada').value #-> "nanoo bar nanoo"
def value
if @value
matches = @value.scan(PEREFERENCE_RE)
rv = @value.clone
if @parent
sum = 0
matches.each do |entity_reference|
entity_value = @parent.entity( entity_reference[0] )
if sum + entity_value.bytesize > Security.entity_expansion_text_limit
raise "entity expansion has grown too large"
else
sum += entity_value.bytesize
end
rv.gsub!( /%#{entity_reference.join};/um, entity_value )
end
end
return rv
end
nil
end
end
# This is a set of entity constants -- the ones defined in the XML
# specification. These are +gt+, +lt+, +amp+, +quot+ and +apos+.
# CAUTION: these entities does not have parent and document
module EntityConst
# +>+
GT = Entity.new( 'gt', '>' )
# +<+
LT = Entity.new( 'lt', '<' )
# +&+
AMP = Entity.new( 'amp', '&' )
# +"+
QUOT = Entity.new( 'quot', '"' )
# +'+
APOS = Entity.new( 'apos', "'" )
end
end

Просмотреть файл

@ -1,116 +0,0 @@
# frozen_string_literal: false
module REXML
module Formatters
class Default
# Prints out the XML document with no formatting -- except if ie_hack is
# set.
#
# ie_hack::
# If set to true, then inserts whitespace before the close of an empty
# tag, so that IE's bad XML parser doesn't choke.
def initialize( ie_hack=false )
@ie_hack = ie_hack
end
# Writes the node to some output.
#
# node::
# The node to write
# output::
# A class implementing <TT>&lt;&lt;</TT>. Pass in an Output object to
# change the output encoding.
def write( node, output )
case node
when Document
if node.xml_decl.encoding != 'UTF-8' && !output.kind_of?(Output)
output = Output.new( output, node.xml_decl.encoding )
end
write_document( node, output )
when Element
write_element( node, output )
when Declaration, ElementDecl, NotationDecl, ExternalEntity, Entity,
Attribute, AttlistDecl
node.write( output,-1 )
when Instruction
write_instruction( node, output )
when DocType, XMLDecl
node.write( output )
when Comment
write_comment( node, output )
when CData
write_cdata( node, output )
when Text
write_text( node, output )
else
raise Exception.new("XML FORMATTING ERROR")
end
end
protected
def write_document( node, output )
node.children.each { |child| write( child, output ) }
end
def write_element( node, output )
output << "<#{node.expanded_name}"
node.attributes.to_a.map { |a|
Hash === a ? a.values : a
}.flatten.sort_by {|attr| attr.name}.each do |attr|
output << " "
attr.write( output )
end unless node.attributes.empty?
if node.children.empty?
output << " " if @ie_hack
output << "/"
else
output << ">"
node.children.each { |child|
write( child, output )
}
output << "</#{node.expanded_name}"
end
output << ">"
end
def write_text( node, output )
output << node.to_s()
end
def write_comment( node, output )
output << Comment::START
output << node.to_s
output << Comment::STOP
end
def write_cdata( node, output )
output << CData::START
output << node.to_s
output << CData::STOP
end
def write_instruction( node, output )
output << Instruction::START
output << node.target
content = node.content
if content
output << ' '
output << content
end
output << Instruction::STOP
end
end
end
end

Просмотреть файл

@ -1,142 +0,0 @@
# frozen_string_literal: false
require_relative 'default'
module REXML
module Formatters
# Pretty-prints an XML document. This destroys whitespace in text nodes
# and will insert carriage returns and indentations.
#
# TODO: Add an option to print attributes on new lines
class Pretty < Default
# If compact is set to true, then the formatter will attempt to use as
# little space as possible
attr_accessor :compact
# The width of a page. Used for formatting text
attr_accessor :width
# Create a new pretty printer.
#
# output::
# An object implementing '<<(String)', to which the output will be written.
# indentation::
# An integer greater than 0. The indentation of each level will be
# this number of spaces. If this is < 1, the behavior of this object
# is undefined. Defaults to 2.
# ie_hack::
# If true, the printer will insert whitespace before closing empty
# tags, thereby allowing Internet Explorer's XML parser to
# function. Defaults to false.
def initialize( indentation=2, ie_hack=false )
@indentation = indentation
@level = 0
@ie_hack = ie_hack
@width = 80
@compact = false
end
protected
def write_element(node, output)
output << ' '*@level
output << "<#{node.expanded_name}"
node.attributes.each_attribute do |attr|
output << " "
attr.write( output )
end unless node.attributes.empty?
if node.children.empty?
if @ie_hack
output << " "
end
output << "/"
else
output << ">"
# If compact and all children are text, and if the formatted output
# is less than the specified width, then try to print everything on
# one line
skip = false
if compact
if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
string = ""
old_level = @level
@level = 0
node.children.each { |child| write( child, string ) }
@level = old_level
if string.length < @width
output << string
skip = true
end
end
end
unless skip
output << "\n"
@level += @indentation
node.children.each { |child|
next if child.kind_of?(Text) and child.to_s.strip.length == 0
write( child, output )
output << "\n"
}
@level -= @indentation
output << ' '*@level
end
output << "</#{node.expanded_name}"
end
output << ">"
end
def write_text( node, output )
s = node.to_s()
s.gsub!(/\s/,' ')
s.squeeze!(" ")
s = wrap(s, @width - @level)
s = indent_text(s, @level, " ", true)
output << (' '*@level + s)
end
def write_comment( node, output)
output << ' ' * @level
super
end
def write_cdata( node, output)
output << ' ' * @level
super
end
def write_document( node, output )
# Ok, this is a bit odd. All XML documents have an XML declaration,
# but it may not write itself if the user didn't specifically add it,
# either through the API or in the input document. If it doesn't write
# itself, then we don't need a carriage return... which makes this
# logic more complex.
node.children.each { |child|
next if child == node.children[-1] and child.instance_of?(Text)
unless child == node.children[0] or child.instance_of?(Text) or
(child == node.children[1] and !node.children[0].writethis)
output << "\n"
end
write( child, output )
}
end
private
def indent_text(string, level=1, style="\t", indentfirstline=true)
return string if level < 0
string.gsub(/\n/, "\n#{style*level}")
end
def wrap(string, width)
parts = []
while string.length > width and place = string.rindex(' ', width)
parts << string[0...place]
string = string[place+1..-1]
end
parts << string
parts.join("\n")
end
end
end
end

Просмотреть файл

@ -1,58 +0,0 @@
# frozen_string_literal: false
require_relative 'pretty'
module REXML
module Formatters
# The Transitive formatter writes an XML document that parses to an
# identical document as the source document. This means that no extra
# whitespace nodes are inserted, and whitespace within text nodes is
# preserved. Within these constraints, the document is pretty-printed,
# with whitespace inserted into the metadata to introduce formatting.
#
# Note that this is only useful if the original XML is not already
# formatted. Since this formatter does not alter whitespace nodes, the
# results of formatting already formatted XML will be odd.
class Transitive < Default
def initialize( indentation=2, ie_hack=false )
@indentation = indentation
@level = 0
@ie_hack = ie_hack
end
protected
def write_element( node, output )
output << "<#{node.expanded_name}"
node.attributes.each_attribute do |attr|
output << " "
attr.write( output )
end unless node.attributes.empty?
output << "\n"
output << ' '*@level
if node.children.empty?
output << " " if @ie_hack
output << "/"
else
output << ">"
# If compact and all children are text, and if the formatted output
# is less than the specified width, then try to print everything on
# one line
@level += @indentation
node.children.each { |child|
write( child, output )
}
@level -= @indentation
output << "</#{node.expanded_name}"
output << "\n"
output << ' '*@level
end
output << ">"
end
def write_text( node, output )
output << node.to_s()
end
end
end
end

Просмотреть файл

@ -1,447 +0,0 @@
# frozen_string_literal: false
module REXML
# If you add a method, keep in mind two things:
# (1) the first argument will always be a list of nodes from which to
# filter. In the case of context methods (such as position), the function
# should return an array with a value for each child in the array.
# (2) all method calls from XML will have "-" replaced with "_".
# Therefore, in XML, "local-name()" is identical (and actually becomes)
# "local_name()"
module Functions
@@available_functions = {}
@@context = nil
@@namespace_context = {}
@@variables = {}
INTERNAL_METHODS = [
:namespace_context,
:namespace_context=,
:variables,
:variables=,
:context=,
:get_namespace,
:send,
]
class << self
def singleton_method_added(name)
unless INTERNAL_METHODS.include?(name)
@@available_functions[name] = true
end
end
end
def Functions::namespace_context=(x) ; @@namespace_context=x ; end
def Functions::variables=(x) ; @@variables=x ; end
def Functions::namespace_context ; @@namespace_context ; end
def Functions::variables ; @@variables ; end
def Functions::context=(value); @@context = value; end
def Functions::text( )
if @@context[:node].node_type == :element
return @@context[:node].find_all{|n| n.node_type == :text}.collect{|n| n.value}
elsif @@context[:node].node_type == :text
return @@context[:node].value
else
return false
end
end
# Returns the last node of the given list of nodes.
def Functions::last( )
@@context[:size]
end
def Functions::position( )
@@context[:index]
end
# Returns the size of the given list of nodes.
def Functions::count( node_set )
node_set.size
end
# Since REXML is non-validating, this method is not implemented as it
# requires a DTD
def Functions::id( object )
end
def Functions::local_name(node_set=nil)
get_namespace(node_set) do |node|
return node.local_name
end
""
end
def Functions::namespace_uri( node_set=nil )
get_namespace( node_set ) {|node| node.namespace}
end
def Functions::name( node_set=nil )
get_namespace( node_set ) do |node|
node.expanded_name
end
end
# Helper method.
def Functions::get_namespace( node_set = nil )
if node_set == nil
yield @@context[:node] if @@context[:node].respond_to?(:namespace)
else
if node_set.respond_to? :each
result = []
node_set.each do |node|
result << yield(node) if node.respond_to?(:namespace)
end
result
elsif node_set.respond_to? :namespace
yield node_set
end
end
end
# A node-set is converted to a string by returning the string-value of the
# node in the node-set that is first in document order. If the node-set is
# empty, an empty string is returned.
#
# A number is converted to a string as follows
#
# NaN is converted to the string NaN
#
# positive zero is converted to the string 0
#
# negative zero is converted to the string 0
#
# positive infinity is converted to the string Infinity
#
# negative infinity is converted to the string -Infinity
#
# if the number is an integer, the number is represented in decimal form
# as a Number with no decimal point and no leading zeros, preceded by a
# minus sign (-) if the number is negative
#
# otherwise, the number is represented in decimal form as a Number
# including a decimal point with at least one digit before the decimal
# point and at least one digit after the decimal point, preceded by a
# minus sign (-) if the number is negative; there must be no leading zeros
# before the decimal point apart possibly from the one required digit
# immediately before the decimal point; beyond the one required digit
# after the decimal point there must be as many, but only as many, more
# digits as are needed to uniquely distinguish the number from all other
# IEEE 754 numeric values.
#
# The boolean false value is converted to the string false. The boolean
# true value is converted to the string true.
#
# An object of a type other than the four basic types is converted to a
# string in a way that is dependent on that type.
def Functions::string( object=@@context[:node] )
if object.respond_to?(:node_type)
case object.node_type
when :attribute
object.value
when :element
string_value(object)
when :document
string_value(object.root)
when :processing_instruction
object.content
else
object.to_s
end
else
case object
when Array
string(object[0])
when Float
if object.nan?
"NaN"
else
integer = object.to_i
if object == integer
"%d" % integer
else
object.to_s
end
end
else
object.to_s
end
end
end
# A node-set is converted to a string by
# returning the concatenation of the string-value
# of each of the children of the node in the
# node-set that is first in document order.
# If the node-set is empty, an empty string is returned.
def Functions::string_value( o )
rv = ""
o.children.each { |e|
if e.node_type == :text
rv << e.to_s
elsif e.node_type == :element
rv << string_value( e )
end
}
rv
end
def Functions::concat( *objects )
concatenated = ""
objects.each do |object|
concatenated << string(object)
end
concatenated
end
# Fixed by Mike Stok
def Functions::starts_with( string, test )
string(string).index(string(test)) == 0
end
# Fixed by Mike Stok
def Functions::contains( string, test )
string(string).include?(string(test))
end
# Kouhei fixed this
def Functions::substring_before( string, test )
ruby_string = string(string)
ruby_index = ruby_string.index(string(test))
if ruby_index.nil?
""
else
ruby_string[ 0...ruby_index ]
end
end
# Kouhei fixed this too
def Functions::substring_after( string, test )
ruby_string = string(string)
return $1 if ruby_string =~ /#{test}(.*)/
""
end
# Take equal portions of Mike Stok and Sean Russell; mix
# vigorously, and pour into a tall, chilled glass. Serves 10,000.
def Functions::substring( string, start, length=nil )
ruby_string = string(string)
ruby_length = if length.nil?
ruby_string.length.to_f
else
number(length)
end
ruby_start = number(start)
# Handle the special cases
return '' if (
ruby_length.nan? or
ruby_start.nan? or
ruby_start.infinite?
)
infinite_length = ruby_length.infinite? == 1
ruby_length = ruby_string.length if infinite_length
# Now, get the bounds. The XPath bounds are 1..length; the ruby bounds
# are 0..length. Therefore, we have to offset the bounds by one.
ruby_start = round(ruby_start) - 1
ruby_length = round(ruby_length)
if ruby_start < 0
ruby_length += ruby_start unless infinite_length
ruby_start = 0
end
return '' if ruby_length <= 0
ruby_string[ruby_start,ruby_length]
end
# UNTESTED
def Functions::string_length( string )
string(string).length
end
# UNTESTED
def Functions::normalize_space( string=nil )
string = string(@@context[:node]) if string.nil?
if string.kind_of? Array
string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string}
else
string.to_s.strip.gsub(/\s+/um, ' ')
end
end
# This is entirely Mike Stok's beast
def Functions::translate( string, tr1, tr2 )
from = string(tr1)
to = string(tr2)
# the map is our translation table.
#
# if a character occurs more than once in the
# from string then we ignore the second &
# subsequent mappings
#
# if a character maps to nil then we delete it
# in the output. This happens if the from
# string is longer than the to string
#
# there's nothing about - or ^ being special in
# http://www.w3.org/TR/xpath#function-translate
# so we don't build ranges or negated classes
map = Hash.new
0.upto(from.length - 1) { |pos|
from_char = from[pos]
unless map.has_key? from_char
map[from_char] =
if pos < to.length
to[pos]
else
nil
end
end
}
if ''.respond_to? :chars
string(string).chars.collect { |c|
if map.has_key? c then map[c] else c end
}.compact.join
else
string(string).unpack('U*').collect { |c|
if map.has_key? c then map[c] else c end
}.compact.pack('U*')
end
end
def Functions::boolean(object=@@context[:node])
case object
when true, false
object
when Float
return false if object.zero?
return false if object.nan?
true
when Numeric
not object.zero?
when String
not object.empty?
when Array
not object.empty?
else
object ? true : false
end
end
# UNTESTED
def Functions::not( object )
not boolean( object )
end
# UNTESTED
def Functions::true( )
true
end
# UNTESTED
def Functions::false( )
false
end
# UNTESTED
def Functions::lang( language )
lang = false
node = @@context[:node]
attr = nil
until node.nil?
if node.node_type == :element
attr = node.attributes["xml:lang"]
unless attr.nil?
lang = compare_language(string(language), attr)
break
else
end
end
node = node.parent
end
lang
end
def Functions::compare_language lang1, lang2
lang2.downcase.index(lang1.downcase) == 0
end
# a string that consists of optional whitespace followed by an optional
# minus sign followed by a Number followed by whitespace is converted to
# the IEEE 754 number that is nearest (according to the IEEE 754
# round-to-nearest rule) to the mathematical value represented by the
# string; any other string is converted to NaN
#
# boolean true is converted to 1; boolean false is converted to 0
#
# a node-set is first converted to a string as if by a call to the string
# function and then converted in the same way as a string argument
#
# an object of a type other than the four basic types is converted to a
# number in a way that is dependent on that type
def Functions::number(object=@@context[:node])
case object
when true
Float(1)
when false
Float(0)
when Array
number(string(object))
when Numeric
object.to_f
else
str = string(object)
case str.strip
when /\A\s*(-?(?:\d+(?:\.\d*)?|\.\d+))\s*\z/
$1.to_f
else
Float::NAN
end
end
end
def Functions::sum( nodes )
nodes = [nodes] unless nodes.kind_of? Array
nodes.inject(0) { |r,n| r + number(string(n)) }
end
def Functions::floor( number )
number(number).floor
end
def Functions::ceiling( number )
number(number).ceil
end
def Functions::round( number )
number = number(number)
begin
neg = number.negative?
number = number.abs.round
neg ? -number : number
rescue FloatDomainError
number
end
end
def Functions::processing_instruction( node )
node.node_type == :processing_instruction
end
def Functions::send(name, *args)
if @@available_functions[name.to_sym]
super
else
# TODO: Maybe, this is not XPath spec behavior.
# This behavior must be reconsidered.
XPath.match(@@context[:node], name.to_s)
end
end
end
end

Просмотреть файл

@ -1,79 +0,0 @@
# frozen_string_literal: false
require_relative "child"
require_relative "source"
module REXML
# Represents an XML Instruction; IE, <? ... ?>
# TODO: Add parent arg (3rd arg) to constructor
class Instruction < Child
START = "<?"
STOP = "?>"
# target is the "name" of the Instruction; IE, the "tag" in <?tag ...?>
# content is everything else.
attr_accessor :target, :content
# Constructs a new Instruction
# @param target can be one of a number of things. If String, then
# the target of this instruction is set to this. If an Instruction,
# then the Instruction is shallowly cloned (target and content are
# copied).
# @param content Must be either a String, or a Parent. Can only
# be a Parent if the target argument is a Source. Otherwise, this
# String is set as the content of this instruction.
def initialize(target, content=nil)
case target
when String
super()
@target = target
@content = content
when Instruction
super(content)
@target = target.target
@content = target.content
else
message =
"processing instruction target must be String or REXML::Instruction: "
message << "<#{target.inspect}>"
raise ArgumentError, message
end
@content.strip! if @content
end
def clone
Instruction.new self
end
# == DEPRECATED
# See the rexml/formatters package
#
def write writer, indent=-1, transitive=false, ie_hack=false
Kernel.warn( "#{self.class.name}.write is deprecated", uplevel: 1)
indent(writer, indent)
writer << START
writer << @target
if @content
writer << ' '
writer << @content
end
writer << STOP
end
# @return true if other is an Instruction, and the content and target
# of the other matches the target and content of this object.
def ==( other )
other.kind_of? Instruction and
other.target == @target and
other.content == @content
end
def node_type
:processing_instruction
end
def inspect
"<?p-i #{target} ...?>"
end
end
end

Просмотреть файл

@ -1,196 +0,0 @@
# frozen_string_literal: false
require_relative '../xmltokens'
# [ :element, parent, name, attributes, children* ]
# a = Node.new
# a << "B" # => <a>B</a>
# a.b # => <a>B<b/></a>
# a.b[1] # => <a>B<b/><b/><a>
# a.b[1]["x"] = "y" # => <a>B<b/><b x="y"/></a>
# a.b[0].c # => <a>B<b><c/></b><b x="y"/></a>
# a.b.c << "D" # => <a>B<b><c>D</c></b><b x="y"/></a>
module REXML
module Light
# Represents a tagged XML element. Elements are characterized by
# having children, attributes, and names, and can themselves be
# children.
class Node
NAMESPLIT = /^(?:(#{XMLTokens::NCNAME_STR}):)?(#{XMLTokens::NCNAME_STR})/u
PARENTS = [ :element, :document, :doctype ]
# Create a new element.
def initialize node=nil
@node = node
if node.kind_of? String
node = [ :text, node ]
elsif node.nil?
node = [ :document, nil, nil ]
elsif node[0] == :start_element
node[0] = :element
elsif node[0] == :start_doctype
node[0] = :doctype
elsif node[0] == :start_document
node[0] = :document
end
end
def size
if PARENTS.include? @node[0]
@node[-1].size
else
0
end
end
def each
size.times { |x| yield( at(x+4) ) }
end
def name
at(2)
end
def name=( name_str, ns=nil )
pfx = ''
pfx = "#{prefix(ns)}:" if ns
_old_put(2, "#{pfx}#{name_str}")
end
def parent=( node )
_old_put(1,node)
end
def local_name
namesplit
@name
end
def local_name=( name_str )
_old_put( 1, "#@prefix:#{name_str}" )
end
def prefix( namespace=nil )
prefix_of( self, namespace )
end
def namespace( prefix=prefix() )
namespace_of( self, prefix )
end
def namespace=( namespace )
@prefix = prefix( namespace )
pfx = ''
pfx = "#@prefix:" if @prefix.size > 0
_old_put(1, "#{pfx}#@name")
end
def []( reference, ns=nil )
if reference.kind_of? String
pfx = ''
pfx = "#{prefix(ns)}:" if ns
at(3)["#{pfx}#{reference}"]
elsif reference.kind_of? Range
_old_get( Range.new(4+reference.begin, reference.end, reference.exclude_end?) )
else
_old_get( 4+reference )
end
end
def =~( path )
XPath.match( self, path )
end
# Doesn't handle namespaces yet
def []=( reference, ns, value=nil )
if reference.kind_of? String
value = ns unless value
at( 3 )[reference] = value
elsif reference.kind_of? Range
_old_put( Range.new(3+reference.begin, reference.end, reference.exclude_end?), ns )
else
if value
_old_put( 4+reference, ns, value )
else
_old_put( 4+reference, ns )
end
end
end
# Append a child to this element, optionally under a provided namespace.
# The namespace argument is ignored if the element argument is an Element
# object. Otherwise, the element argument is a string, the namespace (if
# provided) is the namespace the element is created in.
def << element
if node_type() == :text
at(-1) << element
else
newnode = Node.new( element )
newnode.parent = self
self.push( newnode )
end
at(-1)
end
def node_type
_old_get(0)
end
def text=( foo )
replace = at(4).kind_of?(String)? 1 : 0
self._old_put(4,replace, normalizefoo)
end
def root
context = self
context = context.at(1) while context.at(1)
end
def has_name?( name, namespace = '' )
at(3) == name and namespace() == namespace
end
def children
self
end
def parent
at(1)
end
def to_s
end
private
def namesplit
return if @name.defined?
at(2) =~ NAMESPLIT
@prefix = '' || $1
@name = $2
end
def namespace_of( node, prefix=nil )
if not prefix
name = at(2)
name =~ NAMESPLIT
prefix = $1
end
to_find = 'xmlns'
to_find = "xmlns:#{prefix}" if not prefix.nil?
ns = at(3)[ to_find ]
ns ? ns : namespace_of( @node[0], prefix )
end
def prefix_of( node, namespace=nil )
if not namespace
name = node.name
name =~ NAMESPLIT
$1
else
ns = at(3).find { |k,v| v == namespace }
ns ? ns : prefix_of( node.parent, namespace )
end
end
end
end
end

Просмотреть файл

@ -1,59 +0,0 @@
# frozen_string_literal: false
require_relative 'xmltokens'
module REXML
# Adds named attributes to an object.
module Namespace
# The name of the object, valid if set
attr_reader :name, :expanded_name
# The expanded name of the object, valid if name is set
attr_accessor :prefix
include XMLTokens
NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u
# Sets the name and the expanded name
def name=( name )
@expanded_name = name
case name
when NAMESPLIT
if $1
@prefix = $1
else
@prefix = ""
@namespace = ""
end
@name = $2
when ""
@prefix = nil
@namespace = nil
@name = nil
else
message = "name must be \#{PREFIX}:\#{LOCAL_NAME} or \#{LOCAL_NAME}: "
message += "<#{name.inspect}>"
raise ArgumentError, message
end
end
# Compares names optionally WITH namespaces
def has_name?( other, ns=nil )
if ns
return (namespace() == ns and name() == other)
elsif other.include? ":"
return fully_expanded_name == other
else
return name == other
end
end
alias :local_name :name
# Fully expand the name, even if the prefix wasn't specified in the
# source file.
def fully_expanded_name
ns = prefix
return "#{ns}:#@name" if ns.size > 0
return @name
end
end
end

Просмотреть файл

@ -1,76 +0,0 @@
# frozen_string_literal: false
require_relative "parseexception"
require_relative "formatters/pretty"
require_relative "formatters/default"
module REXML
# Represents a node in the tree. Nodes are never encountered except as
# superclasses of other objects. Nodes have siblings.
module Node
# @return the next sibling (nil if unset)
def next_sibling_node
return nil if @parent.nil?
@parent[ @parent.index(self) + 1 ]
end
# @return the previous sibling (nil if unset)
def previous_sibling_node
return nil if @parent.nil?
ind = @parent.index(self)
return nil if ind == 0
@parent[ ind - 1 ]
end
# indent::
# *DEPRECATED* This parameter is now ignored. See the formatters in the
# REXML::Formatters package for changing the output style.
def to_s indent=nil
unless indent.nil?
Kernel.warn( "#{self.class.name}.to_s(indent) parameter is deprecated", uplevel: 1)
f = REXML::Formatters::Pretty.new( indent )
f.write( self, rv = "" )
else
f = REXML::Formatters::Default.new
f.write( self, rv = "" )
end
return rv
end
def indent to, ind
if @parent and @parent.context and not @parent.context[:indentstyle].nil? then
indentstyle = @parent.context[:indentstyle]
else
indentstyle = ' '
end
to << indentstyle*ind unless ind<1
end
def parent?
false;
end
# Visit all subnodes of +self+ recursively
def each_recursive(&block) # :yields: node
self.elements.each {|node|
block.call(node)
node.each_recursive(&block)
}
end
# Find (and return) first subnode (recursively) for which the block
# evaluates to true. Returns +nil+ if none was found.
def find_first_recursive(&block) # :yields: node
each_recursive {|node|
return node if block.call(node)
}
return nil
end
# Returns the position that +self+ holds in its parent's array, indexed
# from 1.
def index_in_parent
parent.index(self)+1
end
end
end

Просмотреть файл

@ -1,30 +0,0 @@
# frozen_string_literal: false
require_relative 'encoding'
module REXML
class Output
include Encoding
attr_reader :encoding
def initialize real_IO, encd="iso-8859-1"
@output = real_IO
self.encoding = encd
@to_utf = encoding != 'UTF-8'
if encoding == "UTF-16"
@output << "\ufeff".encode("UTF-16BE")
self.encoding = "UTF-16BE"
end
end
def <<( content )
@output << (@to_utf ? self.encode(content) : content)
end
def to_s
"Output[#{encoding}]"
end
end
end

Просмотреть файл

@ -1,166 +0,0 @@
# frozen_string_literal: false
require_relative "child"
module REXML
# A parent has children, and has methods for accessing them. The Parent
# class is never encountered except as the superclass for some other
# object.
class Parent < Child
include Enumerable
# Constructor
# @param parent if supplied, will be set as the parent of this object
def initialize parent=nil
super(parent)
@children = []
end
def add( object )
object.parent = self
@children << object
object
end
alias :push :add
alias :<< :push
def unshift( object )
object.parent = self
@children.unshift object
end
def delete( object )
found = false
@children.delete_if {|c| c.equal?(object) and found = true }
object.parent = nil if found
found ? object : nil
end
def each(&block)
@children.each(&block)
end
def delete_if( &block )
@children.delete_if(&block)
end
def delete_at( index )
@children.delete_at index
end
def each_index( &block )
@children.each_index(&block)
end
# Fetches a child at a given index
# @param index the Integer index of the child to fetch
def []( index )
@children[index]
end
alias :each_child :each
# Set an index entry. See Array.[]=
# @param index the index of the element to set
# @param opt either the object to set, or an Integer length
# @param child if opt is an Integer, this is the child to set
# @return the parent (self)
def []=( *args )
args[-1].parent = self
@children[*args[0..-2]] = args[-1]
end
# Inserts an child before another child
# @param child1 this is either an xpath or an Element. If an Element,
# child2 will be inserted before child1 in the child list of the parent.
# If an xpath, child2 will be inserted before the first child to match
# the xpath.
# @param child2 the child to insert
# @return the parent (self)
def insert_before( child1, child2 )
if child1.kind_of? String
child1 = XPath.first( self, child1 )
child1.parent.insert_before child1, child2
else
ind = index(child1)
child2.parent.delete(child2) if child2.parent
@children[ind,0] = child2
child2.parent = self
end
self
end
# Inserts an child after another child
# @param child1 this is either an xpath or an Element. If an Element,
# child2 will be inserted after child1 in the child list of the parent.
# If an xpath, child2 will be inserted after the first child to match
# the xpath.
# @param child2 the child to insert
# @return the parent (self)
def insert_after( child1, child2 )
if child1.kind_of? String
child1 = XPath.first( self, child1 )
child1.parent.insert_after child1, child2
else
ind = index(child1)+1
child2.parent.delete(child2) if child2.parent
@children[ind,0] = child2
child2.parent = self
end
self
end
def to_a
@children.dup
end
# Fetches the index of a given child
# @param child the child to get the index of
# @return the index of the child, or nil if the object is not a child
# of this parent.
def index( child )
count = -1
@children.find { |i| count += 1 ; i.hash == child.hash }
count
end
# @return the number of children of this parent
def size
@children.size
end
alias :length :size
# Replaces one child with another, making sure the nodelist is correct
# @param to_replace the child to replace (must be a Child)
# @param replacement the child to insert into the nodelist (must be a
# Child)
def replace_child( to_replace, replacement )
@children.map! {|c| c.equal?( to_replace ) ? replacement : c }
to_replace.parent = nil
replacement.parent = self
end
# Deeply clones this object. This creates a complete duplicate of this
# Parent, including all descendants.
def deep_clone
cl = clone()
each do |child|
if child.kind_of? Parent
cl << child.deep_clone
else
cl << child.clone
end
end
cl
end
alias :children :to_a
def parent?
true
end
end
end

Просмотреть файл

@ -1,52 +0,0 @@
# frozen_string_literal: false
module REXML
class ParseException < RuntimeError
attr_accessor :source, :parser, :continued_exception
def initialize( message, source=nil, parser=nil, exception=nil )
super(message)
@source = source
@parser = parser
@continued_exception = exception
end
def to_s
# Quote the original exception, if there was one
if @continued_exception
err = @continued_exception.inspect
err << "\n"
err << @continued_exception.backtrace.join("\n")
err << "\n...\n"
else
err = ""
end
# Get the stack trace and error message
err << super
# Add contextual information
if @source
err << "\nLine: #{line}\n"
err << "Position: #{position}\n"
err << "Last 80 unconsumed characters:\n"
err << @source.buffer[0..80].force_encoding("ASCII-8BIT").gsub(/\n/, ' ')
end
err
end
def position
@source.current_line[0] if @source and defined? @source.current_line and
@source.current_line
end
def line
@source.current_line[2] if @source and defined? @source.current_line and
@source.current_line
end
def context
@source.current_line
end
end
end

Просмотреть файл

@ -1,594 +0,0 @@
# frozen_string_literal: false
require_relative '../parseexception'
require_relative '../undefinednamespaceexception'
require_relative '../source'
require 'set'
require "strscan"
module REXML
module Parsers
# = Using the Pull Parser
# <em>This API is experimental, and subject to change.</em>
# parser = PullParser.new( "<a>text<b att='val'/>txet</a>" )
# while parser.has_next?
# res = parser.next
# puts res[1]['att'] if res.start_tag? and res[0] == 'b'
# end
# See the PullEvent class for information on the content of the results.
# The data is identical to the arguments passed for the various events to
# the StreamListener API.
#
# Notice that:
# parser = PullParser.new( "<a>BAD DOCUMENT" )
# while parser.has_next?
# res = parser.next
# raise res[1] if res.error?
# end
#
# Nat Price gave me some good ideas for the API.
class BaseParser
LETTER = '[:alpha:]'
DIGIT = '[:digit:]'
COMBININGCHAR = '' # TODO
EXTENDER = '' # TODO
NCNAME_STR= "[#{LETTER}_][-[:alnum:]._#{COMBININGCHAR}#{EXTENDER}]*"
QNAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})"
QNAME = /(#{QNAME_STR})/
# Just for backward compatibility. For example, kramdown uses this.
# It's not used in REXML.
UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
NAMECHAR = '[\-\w\.:]'
NAME = "([\\w:]#{NAMECHAR}*)"
NMTOKEN = "(?:#{NAMECHAR})+"
NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*"
REFERENCE = "&(?:#{NAME};|#\\d+;|#x[0-9a-fA-F]+;)"
REFERENCE_RE = /#{REFERENCE}/
DOCTYPE_START = /\A\s*<!DOCTYPE\s/um
DOCTYPE_END = /\A\s*\]\s*>/um
DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
ATTRIBUTE_PATTERN = /\s*(#{QNAME_STR})\s*=\s*(["'])(.*?)\4/um
COMMENT_START = /\A<!--/u
COMMENT_PATTERN = /<!--(.*?)-->/um
CDATA_START = /\A<!\[CDATA\[/u
CDATA_END = /\A\s*\]\s*>/um
CDATA_PATTERN = /<!\[CDATA\[(.*?)\]\]>/um
XMLDECL_START = /\A<\?xml\s/u;
XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um
INSTRUCTION_START = /\A<\?/u
INSTRUCTION_PATTERN = /<\?#{NAME}(\s+.*?)?\?>/um
TAG_MATCH = /^<((?>#{QNAME_STR}))/um
CLOSE_MATCH = /^\s*<\/(#{QNAME_STR})\s*>/um
VERSION = /\bversion\s*=\s*["'](.*?)['"]/um
ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um
STANDALONE = /\bstandalone\s*=\s*["'](.*?)['"]/um
ENTITY_START = /\A\s*<!ENTITY/
IDENTITY = /^([!\*\w\-]+)(\s+#{NCNAME_STR})?(\s+["'](.*?)['"])?(\s+['"](.*?)["'])?/u
ELEMENTDECL_START = /\A\s*<!ELEMENT/um
ELEMENTDECL_PATTERN = /\A\s*(<!ELEMENT.*?)>/um
SYSTEMENTITY = /\A\s*(%.*?;)\s*$/um
ENUMERATION = "\\(\\s*#{NMTOKEN}(?:\\s*\\|\\s*#{NMTOKEN})*\\s*\\)"
NOTATIONTYPE = "NOTATION\\s+\\(\\s*#{NAME}(?:\\s*\\|\\s*#{NAME})*\\s*\\)"
ENUMERATEDTYPE = "(?:(?:#{NOTATIONTYPE})|(?:#{ENUMERATION}))"
ATTTYPE = "(CDATA|ID|IDREF|IDREFS|ENTITY|ENTITIES|NMTOKEN|NMTOKENS|#{ENUMERATEDTYPE})"
ATTVALUE = "(?:\"((?:[^<&\"]|#{REFERENCE})*)\")|(?:'((?:[^<&']|#{REFERENCE})*)')"
DEFAULTDECL = "(#REQUIRED|#IMPLIED|(?:(#FIXED\\s+)?#{ATTVALUE}))"
ATTDEF = "\\s+#{NAME}\\s+#{ATTTYPE}\\s+#{DEFAULTDECL}"
ATTDEF_RE = /#{ATTDEF}/
ATTLISTDECL_START = /\A\s*<!ATTLIST/um
ATTLISTDECL_PATTERN = /\A\s*<!ATTLIST\s+#{NAME}(?:#{ATTDEF})*\s*>/um
NOTATIONDECL_START = /\A\s*<!NOTATION/um
PUBLIC = /\A\s*<!NOTATION\s+(\w[\-\w]*)\s+(PUBLIC)\s+(["'])(.*?)\3(?:\s+(["'])(.*?)\5)?\s*>/um
SYSTEM = /\A\s*<!NOTATION\s+(\w[\-\w]*)\s+(SYSTEM)\s+(["'])(.*?)\3\s*>/um
TEXT_PATTERN = /\A([^<]*)/um
# Entity constants
PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#"
SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))}
PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')}
EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
NDATADECL = "\\s+NDATA\\s+#{NAME}"
PEREFERENCE = "%#{NAME};"
ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
PEDECL = "<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
EREFERENCE = /&(?!#{NAME};)/
DEFAULT_ENTITIES = {
'gt' => [/&gt;/, '&gt;', '>', />/],
'lt' => [/&lt;/, '&lt;', '<', /</],
'quot' => [/&quot;/, '&quot;', '"', /"/],
"apos" => [/&apos;/, "&apos;", "'", /'/]
}
def initialize( source )
self.stream = source
@listeners = []
end
def add_listener( listener )
@listeners << listener
end
attr_reader :source
def stream=( source )
@source = SourceFactory.create_from( source )
@closed = nil
@document_status = nil
@tags = []
@stack = []
@entities = []
@nsstack = []
end
def position
if @source.respond_to? :position
@source.position
else
# FIXME
0
end
end
# Returns true if there are no more events
def empty?
return (@source.empty? and @stack.empty?)
end
# Returns true if there are more events. Synonymous with !empty?
def has_next?
return !(@source.empty? and @stack.empty?)
end
# Push an event back on the head of the stream. This method
# has (theoretically) infinite depth.
def unshift token
@stack.unshift(token)
end
# Peek at the +depth+ event in the stack. The first element on the stack
# is at depth 0. If +depth+ is -1, will parse to the end of the input
# stream and return the last event, which is always :end_document.
# Be aware that this causes the stream to be parsed up to the +depth+
# event, so you can effectively pre-parse the entire document (pull the
# entire thing into memory) using this method.
def peek depth=0
raise %Q[Illegal argument "#{depth}"] if depth < -1
temp = []
if depth == -1
temp.push(pull()) until empty?
else
while @stack.size+temp.size < depth+1
temp.push(pull())
end
end
@stack += temp if temp.size > 0
@stack[depth]
end
# Returns the next event. This is a +PullEvent+ object.
def pull
pull_event.tap do |event|
@listeners.each do |listener|
listener.receive event
end
end
end
def pull_event
if @closed
x, @closed = @closed, nil
return [ :end_element, x ]
end
return [ :end_document ] if empty?
return @stack.shift if @stack.size > 0
#STDERR.puts @source.encoding
@source.read if @source.buffer.size<2
#STDERR.puts "BUFFER = #{@source.buffer.inspect}"
if @document_status == nil
#@source.consume( /^\s*/um )
word = @source.match( /^((?:\s+)|(?:<[^>]*>))/um )
word = word[1] unless word.nil?
#STDERR.puts "WORD = #{word.inspect}"
case word
when COMMENT_START
return [ :comment, @source.match( COMMENT_PATTERN, true )[1] ]
when XMLDECL_START
#STDERR.puts "XMLDECL"
results = @source.match( XMLDECL_PATTERN, true )[1]
version = VERSION.match( results )
version = version[1] unless version.nil?
encoding = ENCODING.match(results)
encoding = encoding[1] unless encoding.nil?
if need_source_encoding_update?(encoding)
@source.encoding = encoding
end
if encoding.nil? and /\AUTF-16(?:BE|LE)\z/i =~ @source.encoding
encoding = "UTF-16"
end
standalone = STANDALONE.match(results)
standalone = standalone[1] unless standalone.nil?
return [ :xmldecl, version, encoding, standalone ]
when INSTRUCTION_START
return process_instruction
when DOCTYPE_START
md = @source.match( DOCTYPE_PATTERN, true )
@nsstack.unshift(curr_ns=Set.new)
identity = md[1]
close = md[2]
identity =~ IDENTITY
name = $1
raise REXML::ParseException.new("DOCTYPE is missing a name") if name.nil?
pub_sys = $2.nil? ? nil : $2.strip
long_name = $4.nil? ? nil : $4.strip
uri = $6.nil? ? nil : $6.strip
args = [ :start_doctype, name, pub_sys, long_name, uri ]
if close == ">"
@document_status = :after_doctype
@source.read if @source.buffer.size<2
md = @source.match(/^\s*/um, true)
@stack << [ :end_doctype ]
else
@document_status = :in_doctype
end
return args
when /^\s+/
else
@document_status = :after_doctype
@source.read if @source.buffer.size<2
md = @source.match(/\s*/um, true)
if @source.encoding == "UTF-8"
@source.buffer.force_encoding(::Encoding::UTF_8)
end
end
end
if @document_status == :in_doctype
md = @source.match(/\s*(.*?>)/um)
case md[1]
when SYSTEMENTITY
match = @source.match( SYSTEMENTITY, true )[1]
return [ :externalentity, match ]
when ELEMENTDECL_START
return [ :elementdecl, @source.match( ELEMENTDECL_PATTERN, true )[1] ]
when ENTITY_START
match = @source.match( ENTITYDECL, true ).to_a.compact
match[0] = :entitydecl
ref = false
if match[1] == '%'
ref = true
match.delete_at 1
end
# Now we have to sort out what kind of entity reference this is
if match[2] == 'SYSTEM'
# External reference
match[3] = match[3][1..-2] # PUBID
match.delete_at(4) if match.size > 4 # Chop out NDATA decl
# match is [ :entity, name, SYSTEM, pubid(, ndata)? ]
elsif match[2] == 'PUBLIC'
# External reference
match[3] = match[3][1..-2] # PUBID
match[4] = match[4][1..-2] # HREF
match.delete_at(5) if match.size > 5 # Chop out NDATA decl
# match is [ :entity, name, PUBLIC, pubid, href(, ndata)? ]
else
match[2] = match[2][1..-2]
match.pop if match.size == 4
# match is [ :entity, name, value ]
end
match << '%' if ref
return match
when ATTLISTDECL_START
md = @source.match( ATTLISTDECL_PATTERN, true )
raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil?
element = md[1]
contents = md[0]
pairs = {}
values = md[0].scan( ATTDEF_RE )
values.each do |attdef|
unless attdef[3] == "#IMPLIED"
attdef.compact!
val = attdef[3]
val = attdef[4] if val == "#FIXED "
pairs[attdef[0]] = val
if attdef[0] =~ /^xmlns:(.*)/
@nsstack[0] << $1
end
end
end
return [ :attlistdecl, element, pairs, contents ]
when NOTATIONDECL_START
md = nil
if @source.match( PUBLIC )
md = @source.match( PUBLIC, true )
vals = [md[1],md[2],md[4],md[6]]
elsif @source.match( SYSTEM )
md = @source.match( SYSTEM, true )
vals = [md[1],md[2],nil,md[4]]
else
raise REXML::ParseException.new( "error parsing notation: no matching pattern", @source )
end
return [ :notationdecl, *vals ]
when DOCTYPE_END
@document_status = :after_doctype
@source.match( DOCTYPE_END, true )
return [ :end_doctype ]
end
end
begin
if @source.buffer[0] == ?<
if @source.buffer[1] == ?/
@nsstack.shift
last_tag = @tags.pop
md = @source.match( CLOSE_MATCH, true )
if md and !last_tag
message = "Unexpected top-level end tag (got '#{md[1]}')"
raise REXML::ParseException.new(message, @source)
end
if md.nil? or last_tag != md[1]
message = "Missing end tag for '#{last_tag}'"
message << " (got '#{md[1]}')" if md
raise REXML::ParseException.new(message, @source)
end
return [ :end_element, last_tag ]
elsif @source.buffer[1] == ?!
md = @source.match(/\A(\s*[^>]*>)/um)
#STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}"
raise REXML::ParseException.new("Malformed node", @source) unless md
if md[0][2] == ?-
md = @source.match( COMMENT_PATTERN, true )
case md[1]
when /--/, /-\z/
raise REXML::ParseException.new("Malformed comment", @source)
end
return [ :comment, md[1] ] if md
else
md = @source.match( CDATA_PATTERN, true )
return [ :cdata, md[1] ] if md
end
raise REXML::ParseException.new( "Declarations can only occur "+
"in the doctype declaration.", @source)
elsif @source.buffer[1] == ??
return process_instruction
else
# Get the next tag
md = @source.match(TAG_MATCH, true)
unless md
raise REXML::ParseException.new("malformed XML: missing tag start", @source)
end
prefixes = Set.new
prefixes << md[2] if md[2]
@nsstack.unshift(curr_ns=Set.new)
attributes, closed = parse_attributes(prefixes, curr_ns)
# Verify that all of the prefixes have been defined
for prefix in prefixes
unless @nsstack.find{|k| k.member?(prefix)}
raise UndefinedNamespaceException.new(prefix,@source,self)
end
end
if closed
@closed = md[1]
@nsstack.shift
else
@tags.push( md[1] )
end
return [ :start_element, md[1], attributes ]
end
else
md = @source.match( TEXT_PATTERN, true )
if md[0].length == 0
@source.match( /(\s+)/, true )
end
#STDERR.puts "GOT #{md[1].inspect}" unless md[0].length == 0
#return [ :text, "" ] if md[0].length == 0
# unnormalized = Text::unnormalize( md[1], self )
# return PullEvent.new( :text, md[1], unnormalized )
return [ :text, md[1] ]
end
rescue REXML::UndefinedNamespaceException
raise
rescue REXML::ParseException
raise
rescue => error
raise REXML::ParseException.new( "Exception parsing",
@source, self, (error ? error : $!) )
end
return [ :dummy ]
end
private :pull_event
def entity( reference, entities )
value = nil
value = entities[ reference ] if entities
if not value
value = DEFAULT_ENTITIES[ reference ]
value = value[2] if value
end
unnormalize( value, entities ) if value
end
# Escapes all possible entities
def normalize( input, entities=nil, entity_filter=nil )
copy = input.clone
# Doing it like this rather than in a loop improves the speed
copy.gsub!( EREFERENCE, '&amp;' )
entities.each do |key, value|
copy.gsub!( value, "&#{key};" ) unless entity_filter and
entity_filter.include?(entity)
end if entities
copy.gsub!( EREFERENCE, '&amp;' )
DEFAULT_ENTITIES.each do |key, value|
copy.gsub!( value[3], value[1] )
end
copy
end
# Unescapes all possible entities
def unnormalize( string, entities=nil, filter=nil )
rv = string.clone
rv.gsub!( /\r\n?/, "\n" )
matches = rv.scan( REFERENCE_RE )
return rv if matches.size == 0
rv.gsub!( /&#0*((?:\d+)|(?:x[a-fA-F0-9]+));/ ) {
m=$1
m = "0#{m}" if m[0] == ?x
[Integer(m)].pack('U*')
}
matches.collect!{|x|x[0]}.compact!
if matches.size > 0
matches.each do |entity_reference|
unless filter and filter.include?(entity_reference)
entity_value = entity( entity_reference, entities )
if entity_value
re = /&#{entity_reference};/
rv.gsub!( re, entity_value )
else
er = DEFAULT_ENTITIES[entity_reference]
rv.gsub!( er[0], er[2] ) if er
end
end
end
rv.gsub!( /&amp;/, '&' )
end
rv
end
private
def need_source_encoding_update?(xml_declaration_encoding)
return false if xml_declaration_encoding.nil?
return false if /\AUTF-16\z/i =~ xml_declaration_encoding
true
end
def process_instruction
match_data = @source.match(INSTRUCTION_PATTERN, true)
unless match_data
message = "Invalid processing instruction node"
raise REXML::ParseException.new(message, @source)
end
[:processing_instruction, match_data[1], match_data[2]]
end
def parse_attributes(prefixes, curr_ns)
attributes = {}
closed = false
match_data = @source.match(/^(.*?)(\/)?>/um, true)
if match_data.nil?
message = "Start tag isn't ended"
raise REXML::ParseException.new(message, @source)
end
raw_attributes = match_data[1]
closed = !match_data[2].nil?
return attributes, closed if raw_attributes.nil?
return attributes, closed if raw_attributes.empty?
scanner = StringScanner.new(raw_attributes)
until scanner.eos?
if scanner.scan(/\s+/)
break if scanner.eos?
end
pos = scanner.pos
loop do
break if scanner.scan(ATTRIBUTE_PATTERN)
unless scanner.scan(QNAME)
message = "Invalid attribute name: <#{scanner.rest}>"
raise REXML::ParseException.new(message, @source)
end
name = scanner[0]
unless scanner.scan(/\s*=\s*/um)
message = "Missing attribute equal: <#{name}>"
raise REXML::ParseException.new(message, @source)
end
quote = scanner.scan(/['"]/)
unless quote
message = "Missing attribute value start quote: <#{name}>"
raise REXML::ParseException.new(message, @source)
end
unless scanner.scan(/.*#{Regexp.escape(quote)}/um)
match_data = @source.match(/^(.*?)(\/)?>/um, true)
if match_data
scanner << "/" if closed
scanner << ">"
scanner << match_data[1]
scanner.pos = pos
closed = !match_data[2].nil?
next
end
message =
"Missing attribute value end quote: <#{name}>: <#{quote}>"
raise REXML::ParseException.new(message, @source)
end
end
name = scanner[1]
prefix = scanner[2]
local_part = scanner[3]
# quote = scanner[4]
value = scanner[5]
if prefix == "xmlns"
if local_part == "xml"
if value != "http://www.w3.org/XML/1998/namespace"
msg = "The 'xml' prefix must not be bound to any other namespace "+
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
raise REXML::ParseException.new( msg, @source, self )
end
elsif local_part == "xmlns"
msg = "The 'xmlns' prefix must not be declared "+
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
raise REXML::ParseException.new( msg, @source, self)
end
curr_ns << local_part
elsif prefix
prefixes << prefix unless prefix == "xml"
end
if attributes.has_key?(name)
msg = "Duplicate attribute #{name.inspect}"
raise REXML::ParseException.new(msg, @source, self)
end
attributes[name] = value
end
return attributes, closed
end
end
end
end
=begin
case event[0]
when :start_element
when :text
when :end_element
when :processing_instruction
when :cdata
when :comment
when :xmldecl
when :start_doctype
when :end_doctype
when :externalentity
when :elementdecl
when :entity
when :attlistdecl
when :notationdecl
when :end_doctype
end
=end

Просмотреть файл

@ -1,59 +0,0 @@
# frozen_string_literal: false
require_relative 'streamparser'
require_relative 'baseparser'
require_relative '../light/node'
module REXML
module Parsers
class LightParser
def initialize stream
@stream = stream
@parser = REXML::Parsers::BaseParser.new( stream )
end
def add_listener( listener )
@parser.add_listener( listener )
end
def rewind
@stream.rewind
@parser.stream = @stream
end
def parse
root = context = [ :document ]
while true
event = @parser.pull
case event[0]
when :end_document
break
when :start_element, :start_doctype
new_node = event
context << new_node
new_node[1,0] = [context]
context = new_node
when :end_element, :end_doctype
context = context[1]
else
new_node = event
context << new_node
new_node[1,0] = [context]
end
end
root
end
end
# An element is an array. The array contains:
# 0 The parent element
# 1 The tag name
# 2 A hash of attributes
# 3..-1 The child elements
# An element is an array of size > 3
# Text is a String
# PIs are [ :processing_instruction, target, data ]
# Comments are [ :comment, data ]
# DocTypes are DocType structs
# The root is an array with XMLDecls, Text, DocType, Array, Text
end
end

Просмотреть файл

@ -1,197 +0,0 @@
# frozen_string_literal: false
require 'forwardable'
require_relative '../parseexception'
require_relative 'baseparser'
require_relative '../xmltokens'
module REXML
module Parsers
# = Using the Pull Parser
# <em>This API is experimental, and subject to change.</em>
# parser = PullParser.new( "<a>text<b att='val'/>txet</a>" )
# while parser.has_next?
# res = parser.next
# puts res[1]['att'] if res.start_tag? and res[0] == 'b'
# end
# See the PullEvent class for information on the content of the results.
# The data is identical to the arguments passed for the various events to
# the StreamListener API.
#
# Notice that:
# parser = PullParser.new( "<a>BAD DOCUMENT" )
# while parser.has_next?
# res = parser.next
# raise res[1] if res.error?
# end
#
# Nat Price gave me some good ideas for the API.
class PullParser
include XMLTokens
extend Forwardable
def_delegators( :@parser, :has_next? )
def_delegators( :@parser, :entity )
def_delegators( :@parser, :empty? )
def_delegators( :@parser, :source )
def initialize stream
@entities = {}
@listeners = nil
@parser = BaseParser.new( stream )
@my_stack = []
end
def add_listener( listener )
@listeners = [] unless @listeners
@listeners << listener
end
def each
while has_next?
yield self.pull
end
end
def peek depth=0
if @my_stack.length <= depth
(depth - @my_stack.length + 1).times {
e = PullEvent.new(@parser.pull)
@my_stack.push(e)
}
end
@my_stack[depth]
end
def pull
return @my_stack.shift if @my_stack.length > 0
event = @parser.pull
case event[0]
when :entitydecl
@entities[ event[1] ] =
event[2] unless event[2] =~ /PUBLIC|SYSTEM/
when :text
unnormalized = @parser.unnormalize( event[1], @entities )
event << unnormalized
end
PullEvent.new( event )
end
def unshift token
@my_stack.unshift token
end
end
# A parsing event. The contents of the event are accessed as an +Array?,
# and the type is given either by the ...? methods, or by accessing the
# +type+ accessor. The contents of this object vary from event to event,
# but are identical to the arguments passed to +StreamListener+s for each
# event.
class PullEvent
# The type of this event. Will be one of :tag_start, :tag_end, :text,
# :processing_instruction, :comment, :doctype, :attlistdecl, :entitydecl,
# :notationdecl, :entity, :cdata, :xmldecl, or :error.
def initialize(arg)
@contents = arg
end
def []( start, endd=nil)
if start.kind_of? Range
@contents.slice( start.begin+1 .. start.end )
elsif start.kind_of? Numeric
if endd.nil?
@contents.slice( start+1 )
else
@contents.slice( start+1, endd )
end
else
raise "Illegal argument #{start.inspect} (#{start.class})"
end
end
def event_type
@contents[0]
end
# Content: [ String tag_name, Hash attributes ]
def start_element?
@contents[0] == :start_element
end
# Content: [ String tag_name ]
def end_element?
@contents[0] == :end_element
end
# Content: [ String raw_text, String unnormalized_text ]
def text?
@contents[0] == :text
end
# Content: [ String text ]
def instruction?
@contents[0] == :processing_instruction
end
# Content: [ String text ]
def comment?
@contents[0] == :comment
end
# Content: [ String name, String pub_sys, String long_name, String uri ]
def doctype?
@contents[0] == :start_doctype
end
# Content: [ String text ]
def attlistdecl?
@contents[0] == :attlistdecl
end
# Content: [ String text ]
def elementdecl?
@contents[0] == :elementdecl
end
# Due to the wonders of DTDs, an entity declaration can be just about
# anything. There's no way to normalize it; you'll have to interpret the
# content yourself. However, the following is true:
#
# * If the entity declaration is an internal entity:
# [ String name, String value ]
# Content: [ String text ]
def entitydecl?
@contents[0] == :entitydecl
end
# Content: [ String text ]
def notationdecl?
@contents[0] == :notationdecl
end
# Content: [ String text ]
def entity?
@contents[0] == :entity
end
# Content: [ String text ]
def cdata?
@contents[0] == :cdata
end
# Content: [ String version, String encoding, String standalone ]
def xmldecl?
@contents[0] == :xmldecl
end
def error?
@contents[0] == :error
end
def inspect
@contents[0].to_s + ": " + @contents[1..-1].inspect
end
end
end
end

Просмотреть файл

@ -1,273 +0,0 @@
# frozen_string_literal: false
require_relative 'baseparser'
require_relative '../parseexception'
require_relative '../namespace'
require_relative '../text'
module REXML
module Parsers
# SAX2Parser
class SAX2Parser
def initialize source
@parser = BaseParser.new(source)
@listeners = []
@procs = []
@namespace_stack = []
@has_listeners = false
@tag_stack = []
@entities = {}
end
def source
@parser.source
end
def add_listener( listener )
@parser.add_listener( listener )
end
# Listen arguments:
#
# Symbol, Array, Block
# Listen to Symbol events on Array elements
# Symbol, Block
# Listen to Symbol events
# Array, Listener
# Listen to all events on Array elements
# Array, Block
# Listen to :start_element events on Array elements
# Listener
# Listen to All events
#
# Symbol can be one of: :start_element, :end_element,
# :start_prefix_mapping, :end_prefix_mapping, :characters,
# :processing_instruction, :doctype, :attlistdecl, :elementdecl,
# :entitydecl, :notationdecl, :cdata, :xmldecl, :comment
#
# There is an additional symbol that can be listened for: :progress.
# This will be called for every event generated, passing in the current
# stream position.
#
# Array contains regular expressions or strings which will be matched
# against fully qualified element names.
#
# Listener must implement the methods in SAX2Listener
#
# Block will be passed the same arguments as a SAX2Listener method would
# be, where the method name is the same as the matched Symbol.
# See the SAX2Listener for more information.
def listen( *args, &blok )
if args[0].kind_of? Symbol
if args.size == 2
args[1].each { |match| @procs << [args[0], match, blok] }
else
add( [args[0], nil, blok] )
end
elsif args[0].kind_of? Array
if args.size == 2
args[0].each { |match| add( [nil, match, args[1]] ) }
else
args[0].each { |match| add( [ :start_element, match, blok ] ) }
end
else
add([nil, nil, args[0]])
end
end
def deafen( listener=nil, &blok )
if listener
@listeners.delete_if {|item| item[-1] == listener }
@has_listeners = false if @listeners.size == 0
else
@procs.delete_if {|item| item[-1] == blok }
end
end
def parse
@procs.each { |sym,match,block| block.call if sym == :start_document }
@listeners.each { |sym,match,block|
block.start_document if sym == :start_document or sym.nil?
}
context = []
while true
event = @parser.pull
case event[0]
when :end_document
handle( :end_document )
break
when :start_doctype
handle( :doctype, *event[1..-1])
when :end_doctype
context = context[1]
when :start_element
@tag_stack.push(event[1])
# find the observers for namespaces
procs = get_procs( :start_prefix_mapping, event[1] )
listeners = get_listeners( :start_prefix_mapping, event[1] )
if procs or listeners
# break out the namespace declarations
# The attributes live in event[2]
event[2].each {|n, v| event[2][n] = @parser.normalize(v)}
nsdecl = event[2].find_all { |n, value| n =~ /^xmlns(:|$)/ }
nsdecl.collect! { |n, value| [ n[6..-1], value ] }
@namespace_stack.push({})
nsdecl.each do |n,v|
@namespace_stack[-1][n] = v
# notify observers of namespaces
procs.each { |ob| ob.call( n, v ) } if procs
listeners.each { |ob| ob.start_prefix_mapping(n, v) } if listeners
end
end
event[1] =~ Namespace::NAMESPLIT
prefix = $1
local = $2
uri = get_namespace(prefix)
# find the observers for start_element
procs = get_procs( :start_element, event[1] )
listeners = get_listeners( :start_element, event[1] )
# notify observers
procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs
listeners.each { |ob|
ob.start_element( uri, local, event[1], event[2] )
} if listeners
when :end_element
@tag_stack.pop
event[1] =~ Namespace::NAMESPLIT
prefix = $1
local = $2
uri = get_namespace(prefix)
# find the observers for start_element
procs = get_procs( :end_element, event[1] )
listeners = get_listeners( :end_element, event[1] )
# notify observers
procs.each { |ob| ob.call( uri, local, event[1] ) } if procs
listeners.each { |ob|
ob.end_element( uri, local, event[1] )
} if listeners
namespace_mapping = @namespace_stack.pop
# find the observers for namespaces
procs = get_procs( :end_prefix_mapping, event[1] )
listeners = get_listeners( :end_prefix_mapping, event[1] )
if procs or listeners
namespace_mapping.each do |ns_prefix, ns_uri|
# notify observers of namespaces
procs.each { |ob| ob.call( ns_prefix ) } if procs
listeners.each { |ob| ob.end_prefix_mapping(ns_prefix) } if listeners
end
end
when :text
#normalized = @parser.normalize( event[1] )
#handle( :characters, normalized )
copy = event[1].clone
esub = proc { |match|
if @entities.has_key?($1)
@entities[$1].gsub(Text::REFERENCE, &esub)
else
match
end
}
copy.gsub!( Text::REFERENCE, &esub )
copy.gsub!( Text::NUMERICENTITY ) {|m|
m=$1
m = "0#{m}" if m[0] == ?x
[Integer(m)].pack('U*')
}
handle( :characters, copy )
when :entitydecl
handle_entitydecl( event )
when :processing_instruction, :comment, :attlistdecl,
:elementdecl, :cdata, :notationdecl, :xmldecl
handle( *event )
end
handle( :progress, @parser.position )
end
end
private
def handle( symbol, *arguments )
tag = @tag_stack[-1]
procs = get_procs( symbol, tag )
listeners = get_listeners( symbol, tag )
# notify observers
procs.each { |ob| ob.call( *arguments ) } if procs
listeners.each { |l|
l.send( symbol.to_s, *arguments )
} if listeners
end
def handle_entitydecl( event )
@entities[ event[1] ] = event[2] if event.size == 3
parameter_reference_p = false
case event[2]
when "SYSTEM"
if event.size == 5
if event.last == "%"
parameter_reference_p = true
else
event[4, 0] = "NDATA"
end
end
when "PUBLIC"
if event.size == 6
if event.last == "%"
parameter_reference_p = true
else
event[5, 0] = "NDATA"
end
end
else
parameter_reference_p = (event.size == 4)
end
event[1, 0] = event.pop if parameter_reference_p
handle( event[0], event[1..-1] )
end
# The following methods are duplicates, but it is faster than using
# a helper
def get_procs( symbol, name )
return nil if @procs.size == 0
@procs.find_all do |sym, match, block|
(
(sym.nil? or symbol == sym) and
((name.nil? and match.nil?) or match.nil? or (
(name == match) or
(match.kind_of? Regexp and name =~ match)
)
)
)
end.collect{|x| x[-1]}
end
def get_listeners( symbol, name )
return nil if @listeners.size == 0
@listeners.find_all do |sym, match, block|
(
(sym.nil? or symbol == sym) and
((name.nil? and match.nil?) or match.nil? or (
(name == match) or
(match.kind_of? Regexp and name =~ match)
)
)
)
end.collect{|x| x[-1]}
end
def add( pair )
if pair[-1].respond_to? :call
@procs << pair unless @procs.include? pair
else
@listeners << pair unless @listeners.include? pair
@has_listeners = true
end
end
def get_namespace( prefix )
uris = (@namespace_stack.find_all { |ns| not ns[prefix].nil? }) ||
(@namespace_stack.find { |ns| not ns[nil].nil? })
uris[-1][prefix] unless uris.nil? or 0 == uris.size
end
end
end
end

Просмотреть файл

@ -1,61 +0,0 @@
# frozen_string_literal: false
require_relative "baseparser"
module REXML
module Parsers
class StreamParser
def initialize source, listener
@listener = listener
@parser = BaseParser.new( source )
@tag_stack = []
end
def add_listener( listener )
@parser.add_listener( listener )
end
def parse
# entity string
while true
event = @parser.pull
case event[0]
when :end_document
unless @tag_stack.empty?
tag_path = "/" + @tag_stack.join("/")
raise ParseException.new("Missing end tag for '#{tag_path}'",
@parser.source)
end
return
when :start_element
@tag_stack << event[1]
attrs = event[2].each do |n, v|
event[2][n] = @parser.unnormalize( v )
end
@listener.tag_start( event[1], attrs )
when :end_element
@listener.tag_end( event[1] )
@tag_stack.pop
when :text
normalized = @parser.unnormalize( event[1] )
@listener.text( normalized )
when :processing_instruction
@listener.instruction( *event[1,2] )
when :start_doctype
@listener.doctype( *event[1..-1] )
when :end_doctype
# FIXME: remove this condition for milestone:3.2
@listener.doctype_end if @listener.respond_to? :doctype_end
when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl
@listener.send( event[0].to_s, *event[1..-1] )
when :entitydecl, :notationdecl
@listener.send( event[0].to_s, event[1..-1] )
when :externalentity
entity_reference = event[1]
content = entity_reference.gsub(/\A%|;\z/, "")
@listener.entity(content)
end
end
end
end
end
end

Просмотреть файл

@ -1,101 +0,0 @@
# frozen_string_literal: false
require_relative '../validation/validationexception'
require_relative '../undefinednamespaceexception'
module REXML
module Parsers
class TreeParser
def initialize( source, build_context = Document.new )
@build_context = build_context
@parser = Parsers::BaseParser.new( source )
end
def add_listener( listener )
@parser.add_listener( listener )
end
def parse
tag_stack = []
in_doctype = false
entities = nil
begin
while true
event = @parser.pull
#STDERR.puts "TREEPARSER GOT #{event.inspect}"
case event[0]
when :end_document
unless tag_stack.empty?
raise ParseException.new("No close tag for #{@build_context.xpath}",
@parser.source, @parser)
end
return
when :start_element
tag_stack.push(event[1])
el = @build_context = @build_context.add_element( event[1] )
event[2].each do |key, value|
el.attributes[key]=Attribute.new(key,value,self)
end
when :end_element
tag_stack.pop
@build_context = @build_context.parent
when :text
if not in_doctype
if @build_context[-1].instance_of? Text
@build_context[-1] << event[1]
else
@build_context.add(
Text.new(event[1], @build_context.whitespace, nil, true)
) unless (
@build_context.ignore_whitespace_nodes and
event[1].strip.size==0
)
end
end
when :comment
c = Comment.new( event[1] )
@build_context.add( c )
when :cdata
c = CData.new( event[1] )
@build_context.add( c )
when :processing_instruction
@build_context.add( Instruction.new( event[1], event[2] ) )
when :end_doctype
in_doctype = false
entities.each { |k,v| entities[k] = @build_context.entities[k].value }
@build_context = @build_context.parent
when :start_doctype
doctype = DocType.new( event[1..-1], @build_context )
@build_context = doctype
entities = {}
in_doctype = true
when :attlistdecl
n = AttlistDecl.new( event[1..-1] )
@build_context.add( n )
when :externalentity
n = ExternalEntity.new( event[1] )
@build_context.add( n )
when :elementdecl
n = ElementDecl.new( event[1] )
@build_context.add(n)
when :entitydecl
entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/
@build_context.add(Entity.new(event))
when :notationdecl
n = NotationDecl.new( *event[1..-1] )
@build_context.add( n )
when :xmldecl
x = XMLDecl.new( event[1], event[2], event[3] )
@build_context.add( x )
end
end
rescue REXML::Validation::ValidationException
raise
rescue REXML::ParseException
raise
rescue
raise ParseException.new( $!.message, @parser.source, @parser, $! )
end
end
end
end
end

Просмотреть файл

@ -1,57 +0,0 @@
# frozen_string_literal: false
require_relative 'streamparser'
require_relative 'baseparser'
module REXML
module Parsers
class UltraLightParser
def initialize stream
@stream = stream
@parser = REXML::Parsers::BaseParser.new( stream )
end
def add_listener( listener )
@parser.add_listener( listener )
end
def rewind
@stream.rewind
@parser.stream = @stream
end
def parse
root = context = []
while true
event = @parser.pull
case event[0]
when :end_document
break
when :end_doctype
context = context[1]
when :start_element, :start_doctype
context << event
event[1,0] = [context]
context = event
when :end_element
context = context[1]
else
context << event
end
end
root
end
end
# An element is an array. The array contains:
# 0 The parent element
# 1 The tag name
# 2 A hash of attributes
# 3..-1 The child elements
# An element is an array of size > 3
# Text is a String
# PIs are [ :processing_instruction, target, data ]
# Comments are [ :comment, data ]
# DocTypes are DocType structs
# The root is an array with XMLDecls, Text, DocType, Array, Text
end
end

Просмотреть файл

@ -1,675 +0,0 @@
# frozen_string_literal: false
require_relative '../namespace'
require_relative '../xmltokens'
module REXML
module Parsers
# You don't want to use this class. Really. Use XPath, which is a wrapper
# for this class. Believe me. You don't want to poke around in here.
# There is strange, dark magic at work in this code. Beware. Go back! Go
# back while you still can!
class XPathParser
include XMLTokens
LITERAL = /^'([^']*)'|^"([^"]*)"/u
def namespaces=( namespaces )
Functions::namespace_context = namespaces
@namespaces = namespaces
end
def parse path
path = path.dup
path.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces
path.gsub!( /\s+([\]\)])/, '\1')
parsed = []
OrExpr(path, parsed)
parsed
end
def predicate path
parsed = []
Predicate( "[#{path}]", parsed )
parsed
end
def abbreviate( path )
path = path.kind_of?(String) ? parse( path ) : path
string = ""
document = false
while path.size > 0
op = path.shift
case op
when :node
when :attribute
string << "/" if string.size > 0
string << "@"
when :child
string << "/" if string.size > 0
when :descendant_or_self
string << "/"
when :self
string << "."
when :parent
string << ".."
when :any
string << "*"
when :text
string << "text()"
when :following, :following_sibling,
:ancestor, :ancestor_or_self, :descendant,
:namespace, :preceding, :preceding_sibling
string << "/" unless string.size == 0
string << op.to_s.tr("_", "-")
string << "::"
when :qname
prefix = path.shift
name = path.shift
string << prefix+":" if prefix.size > 0
string << name
when :predicate
string << '['
string << predicate_to_string( path.shift ) {|x| abbreviate( x ) }
string << ']'
when :document
document = true
when :function
string << path.shift
string << "( "
string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
string << " )"
when :literal
string << %Q{ "#{path.shift}" }
else
string << "/" unless string.size == 0
string << "UNKNOWN("
string << op.inspect
string << ")"
end
end
string = "/"+string if document
return string
end
def expand( path )
path = path.kind_of?(String) ? parse( path ) : path
string = ""
document = false
while path.size > 0
op = path.shift
case op
when :node
string << "node()"
when :attribute, :child, :following, :following_sibling,
:ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
:namespace, :preceding, :preceding_sibling, :self, :parent
string << "/" unless string.size == 0
string << op.to_s.tr("_", "-")
string << "::"
when :any
string << "*"
when :qname
prefix = path.shift
name = path.shift
string << prefix+":" if prefix.size > 0
string << name
when :predicate
string << '['
string << predicate_to_string( path.shift ) { |x| expand(x) }
string << ']'
when :document
document = true
else
string << "/" unless string.size == 0
string << "UNKNOWN("
string << op.inspect
string << ")"
end
end
string = "/"+string if document
return string
end
def predicate_to_string( path, &block )
string = ""
case path[0]
when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
op = path.shift
case op
when :eq
op = "="
when :lt
op = "<"
when :gt
op = ">"
when :lteq
op = "<="
when :gteq
op = ">="
when :neq
op = "!="
when :union
op = "|"
end
left = predicate_to_string( path.shift, &block )
right = predicate_to_string( path.shift, &block )
string << " "
string << left
string << " "
string << op.to_s
string << " "
string << right
string << " "
when :function
path.shift
name = path.shift
string << name
string << "( "
string << predicate_to_string( path.shift, &block )
string << " )"
when :literal
path.shift
string << " "
string << path.shift.inspect
string << " "
else
string << " "
string << yield( path )
string << " "
end
return string.squeeze(" ")
end
private
#LocationPath
# | RelativeLocationPath
# | '/' RelativeLocationPath?
# | '//' RelativeLocationPath
def LocationPath path, parsed
path = path.lstrip
if path[0] == ?/
parsed << :document
if path[1] == ?/
parsed << :descendant_or_self
parsed << :node
path = path[2..-1]
else
path = path[1..-1]
end
end
return RelativeLocationPath( path, parsed ) if path.size > 0
end
#RelativeLocationPath
# | Step
# | (AXIS_NAME '::' | '@' | '') AxisSpecifier
# NodeTest
# Predicate
# | '.' | '..' AbbreviatedStep
# | RelativeLocationPath '/' Step
# | RelativeLocationPath '//' Step
AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/
def RelativeLocationPath path, parsed
loop do
original_path = path
path = path.lstrip
return original_path if path.empty?
# (axis or @ or <child::>) nodetest predicate >
# OR > / Step
# (. or ..) >
if path[0] == ?.
if path[1] == ?.
parsed << :parent
parsed << :node
path = path[2..-1]
else
parsed << :self
parsed << :node
path = path[1..-1]
end
else
if path[0] == ?@
parsed << :attribute
path = path[1..-1]
# Goto Nodetest
elsif path =~ AXIS
parsed << $1.tr('-','_').intern
path = $'
# Goto Nodetest
else
parsed << :child
end
n = []
path = NodeTest( path, n)
path = Predicate( path, n )
parsed.concat(n)
end
original_path = path
path = path.lstrip
return original_path if path.empty?
return original_path if path[0] != ?/
if path[1] == ?/
parsed << :descendant_or_self
parsed << :node
path = path[2..-1]
else
path = path[1..-1]
end
end
end
# Returns a 1-1 map of the nodeset
# The contents of the resulting array are either:
# true/false, if a positive match
# String, if a name match
#NodeTest
# | ('*' | NCNAME ':' '*' | QNAME) NameTest
# | '*' ':' NCNAME NameTest since XPath 2.0
# | NODE_TYPE '(' ')' NodeType
# | PI '(' LITERAL ')' PI
# | '[' expr ']' Predicate
PREFIX_WILDCARD = /^\*:(#{NCNAME_STR})/u
LOCAL_NAME_WILDCARD = /^(#{NCNAME_STR}):\*/u
QNAME = Namespace::NAMESPLIT
NODE_TYPE = /^(comment|text|node)\(\s*\)/m
PI = /^processing-instruction\(/
def NodeTest path, parsed
original_path = path
path = path.lstrip
case path
when PREFIX_WILDCARD
prefix = nil
name = $1
path = $'
parsed << :qname
parsed << prefix
parsed << name
when /^\*/
path = $'
parsed << :any
when NODE_TYPE
type = $1
path = $'
parsed << type.tr('-', '_').intern
when PI
path = $'
literal = nil
if path !~ /^\s*\)/
path =~ LITERAL
literal = $1
path = $'
raise ParseException.new("Missing ')' after processing instruction") if path[0] != ?)
path = path[1..-1]
end
parsed << :processing_instruction
parsed << (literal || '')
when LOCAL_NAME_WILDCARD
prefix = $1
path = $'
parsed << :namespace
parsed << prefix
when QNAME
prefix = $1
name = $2
path = $'
prefix = "" unless prefix
parsed << :qname
parsed << prefix
parsed << name
else
path = original_path
end
return path
end
# Filters the supplied nodeset on the predicate(s)
def Predicate path, parsed
original_path = path
path = path.lstrip
return original_path unless path[0] == ?[
predicates = []
while path[0] == ?[
path, expr = get_group(path)
predicates << expr[1..-2] if expr
end
predicates.each{ |pred|
preds = []
parsed << :predicate
parsed << preds
OrExpr(pred, preds)
}
path
end
# The following return arrays of true/false, a 1-1 mapping of the
# supplied nodeset, except for axe(), which returns a filtered
# nodeset
#| OrExpr S 'or' S AndExpr
#| AndExpr
def OrExpr path, parsed
n = []
rest = AndExpr( path, n )
if rest != path
while rest =~ /^\s*( or )/
n = [ :or, n, [] ]
rest = AndExpr( $', n[-1] )
end
end
if parsed.size == 0 and n.size != 0
parsed.replace(n)
elsif n.size > 0
parsed << n
end
rest
end
#| AndExpr S 'and' S EqualityExpr
#| EqualityExpr
def AndExpr path, parsed
n = []
rest = EqualityExpr( path, n )
if rest != path
while rest =~ /^\s*( and )/
n = [ :and, n, [] ]
rest = EqualityExpr( $', n[-1] )
end
end
if parsed.size == 0 and n.size != 0
parsed.replace(n)
elsif n.size > 0
parsed << n
end
rest
end
#| EqualityExpr ('=' | '!=') RelationalExpr
#| RelationalExpr
def EqualityExpr path, parsed
n = []
rest = RelationalExpr( path, n )
if rest != path
while rest =~ /^\s*(!?=)\s*/
if $1[0] == ?!
n = [ :neq, n, [] ]
else
n = [ :eq, n, [] ]
end
rest = RelationalExpr( $', n[-1] )
end
end
if parsed.size == 0 and n.size != 0
parsed.replace(n)
elsif n.size > 0
parsed << n
end
rest
end
#| RelationalExpr ('<' | '>' | '<=' | '>=') AdditiveExpr
#| AdditiveExpr
def RelationalExpr path, parsed
n = []
rest = AdditiveExpr( path, n )
if rest != path
while rest =~ /^\s*([<>]=?)\s*/
if $1[0] == ?<
sym = "lt"
else
sym = "gt"
end
sym << "eq" if $1[-1] == ?=
n = [ sym.intern, n, [] ]
rest = AdditiveExpr( $', n[-1] )
end
end
if parsed.size == 0 and n.size != 0
parsed.replace(n)
elsif n.size > 0
parsed << n
end
rest
end
#| AdditiveExpr ('+' | '-') MultiplicativeExpr
#| MultiplicativeExpr
def AdditiveExpr path, parsed
n = []
rest = MultiplicativeExpr( path, n )
if rest != path
while rest =~ /^\s*(\+|-)\s*/
if $1[0] == ?+
n = [ :plus, n, [] ]
else
n = [ :minus, n, [] ]
end
rest = MultiplicativeExpr( $', n[-1] )
end
end
if parsed.size == 0 and n.size != 0
parsed.replace(n)
elsif n.size > 0
parsed << n
end
rest
end
#| MultiplicativeExpr ('*' | S ('div' | 'mod') S) UnaryExpr
#| UnaryExpr
def MultiplicativeExpr path, parsed
n = []
rest = UnaryExpr( path, n )
if rest != path
while rest =~ /^\s*(\*| div | mod )\s*/
if $1[0] == ?*
n = [ :mult, n, [] ]
elsif $1.include?( "div" )
n = [ :div, n, [] ]
else
n = [ :mod, n, [] ]
end
rest = UnaryExpr( $', n[-1] )
end
end
if parsed.size == 0 and n.size != 0
parsed.replace(n)
elsif n.size > 0
parsed << n
end
rest
end
#| '-' UnaryExpr
#| UnionExpr
def UnaryExpr path, parsed
path =~ /^(\-*)/
path = $'
if $1 and (($1.size % 2) != 0)
mult = -1
else
mult = 1
end
parsed << :neg if mult < 0
n = []
path = UnionExpr( path, n )
parsed.concat( n )
path
end
#| UnionExpr '|' PathExpr
#| PathExpr
def UnionExpr path, parsed
n = []
rest = PathExpr( path, n )
if rest != path
while rest =~ /^\s*(\|)\s*/
n = [ :union, n, [] ]
rest = PathExpr( $', n[-1] )
end
end
if parsed.size == 0 and n.size != 0
parsed.replace( n )
elsif n.size > 0
parsed << n
end
rest
end
#| LocationPath
#| FilterExpr ('/' | '//') RelativeLocationPath
def PathExpr path, parsed
path = path.lstrip
n = []
rest = FilterExpr( path, n )
if rest != path
if rest and rest[0] == ?/
rest = RelativeLocationPath(rest, n)
parsed.concat(n)
return rest
end
end
rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
parsed.concat(n)
return rest
end
#| FilterExpr Predicate
#| PrimaryExpr
def FilterExpr path, parsed
n = []
path = PrimaryExpr( path, n )
path = Predicate(path, n)
parsed.concat(n)
path
end
#| VARIABLE_REFERENCE
#| '(' expr ')'
#| LITERAL
#| NUMBER
#| FunctionCall
VARIABLE_REFERENCE = /^\$(#{NAME_STR})/u
NUMBER = /^(\d*\.?\d+)/
NT = /^comment|text|processing-instruction|node$/
def PrimaryExpr path, parsed
case path
when VARIABLE_REFERENCE
varname = $1
path = $'
parsed << :variable
parsed << varname
#arry << @variables[ varname ]
when /^(\w[-\w]*)(?:\()/
fname = $1
tmp = $'
return path if fname =~ NT
path = tmp
parsed << :function
parsed << fname
path = FunctionCall(path, parsed)
when NUMBER
varname = $1.nil? ? $2 : $1
path = $'
parsed << :literal
parsed << (varname.include?('.') ? varname.to_f : varname.to_i)
when LITERAL
varname = $1.nil? ? $2 : $1
path = $'
parsed << :literal
parsed << varname
when /^\(/ #/
path, contents = get_group(path)
contents = contents[1..-2]
n = []
OrExpr( contents, n )
parsed.concat(n)
end
path
end
#| FUNCTION_NAME '(' ( expr ( ',' expr )* )? ')'
def FunctionCall rest, parsed
path, arguments = parse_args(rest)
argset = []
for argument in arguments
args = []
OrExpr( argument, args )
argset << args
end
parsed << argset
path
end
# get_group( '[foo]bar' ) -> ['bar', '[foo]']
def get_group string
ind = 0
depth = 0
st = string[0,1]
en = (st == "(" ? ")" : "]")
begin
case string[ind,1]
when st
depth += 1
when en
depth -= 1
end
ind += 1
end while depth > 0 and ind < string.length
return nil unless depth==0
[string[ind..-1], string[0..ind-1]]
end
def parse_args( string )
arguments = []
ind = 0
inquot = false
inapos = false
depth = 1
begin
case string[ind]
when ?"
inquot = !inquot unless inapos
when ?'
inapos = !inapos unless inquot
else
unless inquot or inapos
case string[ind]
when ?(
depth += 1
if depth == 1
string = string[1..-1]
ind -= 1
end
when ?)
depth -= 1
if depth == 0
s = string[0,ind].strip
arguments << s unless s == ""
string = string[ind+1..-1]
end
when ?,
if depth == 1
s = string[0,ind].strip
arguments << s unless s == ""
string = string[ind+1..-1]
ind = -1
end
end
end
end
ind += 1
end while depth > 0 and ind < string.length
return nil unless depth==0
[string,arguments]
end
end
end
end

Просмотреть файл

@ -1,266 +0,0 @@
# frozen_string_literal: false
require_relative 'functions'
require_relative 'xmltokens'
module REXML
class QuickPath
include Functions
include XMLTokens
# A base Hash object to be used when initializing a
# default empty namespaces set.
EMPTY_HASH = {}
def QuickPath::first element, path, namespaces=EMPTY_HASH
match(element, path, namespaces)[0]
end
def QuickPath::each element, path, namespaces=EMPTY_HASH, &block
path = "*" unless path
match(element, path, namespaces).each( &block )
end
def QuickPath::match element, path, namespaces=EMPTY_HASH
raise "nil is not a valid xpath" unless path
results = nil
Functions::namespace_context = namespaces
case path
when /^\/([^\/]|$)/u
# match on root
path = path[1..-1]
return [element.root.parent] if path == ''
results = filter([element.root], path)
when /^[-\w]*::/u
results = filter([element], path)
when /^\*/u
results = filter(element.to_a, path)
when /^[\[!\w:]/u
# match on child
children = element.to_a
results = filter(children, path)
else
results = filter([element], path)
end
return results
end
# Given an array of nodes it filters the array based on the path. The
# result is that when this method returns, the array will contain elements
# which match the path
def QuickPath::filter elements, path
return elements if path.nil? or path == '' or elements.size == 0
case path
when /^\/\//u # Descendant
return axe( elements, "descendant-or-self", $' )
when /^\/?\b(\w[-\w]*)\b::/u # Axe
return axe( elements, $1, $' )
when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u # Child
rest = $'
results = []
elements.each do |element|
results |= filter( element.to_a, rest )
end
return results
when /^\/?(\w[-\w]*)\(/u # / Function
return function( elements, $1, $' )
when Namespace::NAMESPLIT # Element name
name = $2
ns = $1
rest = $'
elements.delete_if do |element|
!(element.kind_of? Element and
(element.expanded_name == name or
(element.name == name and
element.namespace == Functions.namespace_context[ns])))
end
return filter( elements, rest )
when /^\/\[/u
matches = []
elements.each do |element|
matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element
end
return matches
when /^\[/u # Predicate
return predicate( elements, path )
when /^\/?\.\.\./u # Ancestor
return axe( elements, "ancestor", $' )
when /^\/?\.\./u # Parent
return filter( elements.collect{|e|e.parent}, $' )
when /^\/?\./u # Self
return filter( elements, $' )
when /^\*/u # Any
results = []
elements.each do |element|
results |= filter( [element], $' ) if element.kind_of? Element
#if element.kind_of? Element
# children = element.to_a
# children.delete_if { |child| !child.kind_of?(Element) }
# results |= filter( children, $' )
#end
end
return results
end
return []
end
def QuickPath::axe( elements, axe_name, rest )
matches = []
matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u
case axe_name
when /^descendant/u
elements.each do |element|
matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element
end
when /^ancestor/u
elements.each do |element|
while element.parent
matches << element.parent
element = element.parent
end
end
matches = filter( matches, rest )
when "self"
matches = filter( elements, rest )
when "child"
elements.each do |element|
matches |= filter( element.to_a, rest ) if element.kind_of? Element
end
when "attribute"
elements.each do |element|
matches << element.attributes[ rest ] if element.kind_of? Element
end
when "parent"
matches = filter(elements.collect{|element| element.parent}.uniq, rest)
when "following-sibling"
matches = filter(elements.collect{|element| element.next_sibling}.uniq,
rest)
when "previous-sibling"
matches = filter(elements.collect{|element|
element.previous_sibling}.uniq, rest )
end
return matches.uniq
end
OPERAND_ = '((?=(?:(?!and|or).)*[^\s<>=])[^\s<>=]+)'
# A predicate filters a node-set with respect to an axis to produce a
# new node-set. For each node in the node-set to be filtered, the
# PredicateExpr is evaluated with that node as the context node, with
# the number of nodes in the node-set as the context size, and with the
# proximity position of the node in the node-set with respect to the
# axis as the context position; if PredicateExpr evaluates to true for
# that node, the node is included in the new node-set; otherwise, it is
# not included.
#
# A PredicateExpr is evaluated by evaluating the Expr and converting
# the result to a boolean. If the result is a number, the result will
# be converted to true if the number is equal to the context position
# and will be converted to false otherwise; if the result is not a
# number, then the result will be converted as if by a call to the
# boolean function. Thus a location path para[3] is equivalent to
# para[position()=3].
def QuickPath::predicate( elements, path )
ind = 1
bcount = 1
while bcount > 0
bcount += 1 if path[ind] == ?[
bcount -= 1 if path[ind] == ?]
ind += 1
end
ind -= 1
predicate = path[1..ind-1]
rest = path[ind+1..-1]
# have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c'
#
predicate.gsub!(
/#{OPERAND_}\s*([<>=])\s*#{OPERAND_}\s*([<>=])\s*#{OPERAND_}/u,
'\1 \2 \3 and \3 \4 \5' )
# Let's do some Ruby trickery to avoid some work:
predicate.gsub!( /&/u, "&&" )
predicate.gsub!( /=/u, "==" )
predicate.gsub!( /@(\w[-\w.]*)/u, 'attribute("\1")' )
predicate.gsub!( /\bmod\b/u, "%" )
predicate.gsub!( /\b(\w[-\w.]*\()/u ) {
fname = $1
fname.gsub( /-/u, "_" )
}
Functions.pair = [ 0, elements.size ]
results = []
elements.each do |element|
Functions.pair[0] += 1
Functions.node = element
res = eval( predicate )
case res
when true
results << element
when Integer
results << element if Functions.pair[0] == res
when String
results << element
end
end
return filter( results, rest )
end
def QuickPath::attribute( name )
return Functions.node.attributes[name] if Functions.node.kind_of? Element
end
def QuickPath::name()
return Functions.node.name if Functions.node.kind_of? Element
end
def QuickPath::method_missing( id, *args )
begin
Functions.send( id.id2name, *args )
rescue Exception
raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}"
end
end
def QuickPath::function( elements, fname, rest )
args = parse_args( elements, rest )
Functions.pair = [0, elements.size]
results = []
elements.each do |element|
Functions.pair[0] += 1
Functions.node = element
res = Functions.send( fname, *args )
case res
when true
results << element
when Integer
results << element if Functions.pair[0] == res
end
end
return results
end
def QuickPath::parse_args( element, string )
# /.*?(?:\)|,)/
arguments = []
buffer = ""
while string and string != ""
c = string[0]
string.sub!(/^./u, "")
case c
when ?,
# if depth = 1, then we start a new argument
arguments << evaluate( buffer )
#arguments << evaluate( string[0..count] )
when ?(
# start a new method call
function( element, buffer, string )
buffer = ""
when ?)
# close the method call and return arguments
return arguments
else
buffer << c
end
end
""
end
end
end

Просмотреть файл

@ -1,84 +0,0 @@
begin
require_relative "lib/rexml/rexml"
rescue LoadError
# for Ruby core repository
require_relative "rexml"
end
Gem::Specification.new do |spec|
spec.name = "rexml"
spec.version = REXML::VERSION
spec.authors = ["Kouhei Sutou"]
spec.email = ["kou@cozmixng.org"]
spec.summary = %q{An XML toolkit for Ruby}
spec.description = %q{An XML toolkit for Ruby}
spec.homepage = "https://github.com/ruby/rexml"
spec.license = "BSD-2-Clause"
spec.files = [
".gitignore",
".travis.yml",
"Gemfile",
"LICENSE.txt",
"NEWS.md",
"README.md",
"Rakefile",
"lib/rexml/attlistdecl.rb",
"lib/rexml/attribute.rb",
"lib/rexml/cdata.rb",
"lib/rexml/child.rb",
"lib/rexml/comment.rb",
"lib/rexml/doctype.rb",
"lib/rexml/document.rb",
"lib/rexml/dtd/attlistdecl.rb",
"lib/rexml/dtd/dtd.rb",
"lib/rexml/dtd/elementdecl.rb",
"lib/rexml/dtd/entitydecl.rb",
"lib/rexml/dtd/notationdecl.rb",
"lib/rexml/element.rb",
"lib/rexml/encoding.rb",
"lib/rexml/entity.rb",
"lib/rexml/formatters/default.rb",
"lib/rexml/formatters/pretty.rb",
"lib/rexml/formatters/transitive.rb",
"lib/rexml/functions.rb",
"lib/rexml/instruction.rb",
"lib/rexml/light/node.rb",
"lib/rexml/namespace.rb",
"lib/rexml/node.rb",
"lib/rexml/output.rb",
"lib/rexml/parent.rb",
"lib/rexml/parseexception.rb",
"lib/rexml/parsers/baseparser.rb",
"lib/rexml/parsers/lightparser.rb",
"lib/rexml/parsers/pullparser.rb",
"lib/rexml/parsers/sax2parser.rb",
"lib/rexml/parsers/streamparser.rb",
"lib/rexml/parsers/treeparser.rb",
"lib/rexml/parsers/ultralightparser.rb",
"lib/rexml/parsers/xpathparser.rb",
"lib/rexml/quickpath.rb",
"lib/rexml/rexml.rb",
"lib/rexml/sax2listener.rb",
"lib/rexml/security.rb",
"lib/rexml/source.rb",
"lib/rexml/streamlistener.rb",
"lib/rexml/text.rb",
"lib/rexml/undefinednamespaceexception.rb",
"lib/rexml/validation/relaxng.rb",
"lib/rexml/validation/validation.rb",
"lib/rexml/validation/validationexception.rb",
"lib/rexml/xmldecl.rb",
"lib/rexml/xmltokens.rb",
"lib/rexml/xpath.rb",
"lib/rexml/xpath_parser.rb",
"rexml.gemspec",
]
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler"
spec.add_development_dependency "rake"
end

Просмотреть файл

@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
# frozen_string_literal: false
# REXML is an XML toolkit for Ruby[http://www.ruby-lang.org], in Ruby.
#
# REXML is a _pure_ Ruby, XML 1.0 conforming,
# non-validating[http://www.w3.org/TR/2004/REC-xml-20040204/#sec-conformance]
# toolkit with an intuitive API. REXML passes 100% of the non-validating Oasis
# tests[http://www.oasis-open.org/committees/xml-conformance/xml-test-suite.shtml],
# and provides tree, stream, SAX2, pull, and lightweight APIs. REXML also
# includes a full XPath[http://www.w3c.org/tr/xpath] 1.0 implementation. Since
# Ruby 1.8, REXML is included in the standard Ruby distribution.
#
# Main page:: http://www.germane-software.com/software/rexml
# Author:: Sean Russell <serATgermaneHYPHENsoftwareDOTcom>
# Date:: 2008/019
# Version:: 3.1.7.3
#
# This API documentation can be downloaded from the REXML home page, or can
# be accessed online[http://www.germane-software.com/software/rexml_doc]
#
# A tutorial is available in the REXML distribution in docs/tutorial.html,
# or can be accessed
# online[http://www.germane-software.com/software/rexml/docs/tutorial.html]
module REXML
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
DATE = "2008/019"
VERSION = "3.2.3"
REVISION = ""
Copyright = COPYRIGHT
Version = VERSION
end

Просмотреть файл

@ -1,98 +0,0 @@
# frozen_string_literal: false
module REXML
# A template for stream parser listeners.
# Note that the declarations (attlistdecl, elementdecl, etc) are trivially
# processed; REXML doesn't yet handle doctype entity declarations, so you
# have to parse them out yourself.
# === Missing methods from SAX2
# ignorable_whitespace
# === Methods extending SAX2
# +WARNING+
# These methods are certainly going to change, until DTDs are fully
# supported. Be aware of this.
# start_document
# end_document
# doctype
# elementdecl
# attlistdecl
# entitydecl
# notationdecl
# cdata
# xmldecl
# comment
module SAX2Listener
def start_document
end
def end_document
end
def start_prefix_mapping prefix, uri
end
def end_prefix_mapping prefix
end
def start_element uri, localname, qname, attributes
end
def end_element uri, localname, qname
end
def characters text
end
def processing_instruction target, data
end
# Handles a doctype declaration. Any attributes of the doctype which are
# not supplied will be nil. # EG, <!DOCTYPE me PUBLIC "foo" "bar">
# @p name the name of the doctype; EG, "me"
# @p pub_sys "PUBLIC", "SYSTEM", or nil. EG, "PUBLIC"
# @p long_name the supplied long name, or nil. EG, "foo"
# @p uri the uri of the doctype, or nil. EG, "bar"
def doctype name, pub_sys, long_name, uri
end
# If a doctype includes an ATTLIST declaration, it will cause this
# method to be called. The content is the declaration itself, unparsed.
# EG, <!ATTLIST el attr CDATA #REQUIRED> will come to this method as "el
# attr CDATA #REQUIRED". This is the same for all of the .*decl
# methods.
def attlistdecl(element, pairs, contents)
end
# <!ELEMENT ...>
def elementdecl content
end
# <!ENTITY ...>
# The argument passed to this method is an array of the entity
# declaration. It can be in a number of formats, but in general it
# returns (example, result):
# <!ENTITY % YN '"Yes"'>
# ["%", "YN", "\"Yes\""]
# <!ENTITY % YN 'Yes'>
# ["%", "YN", "Yes"]
# <!ENTITY WhatHeSaid "He said %YN;">
# ["WhatHeSaid", "He said %YN;"]
# <!ENTITY open-hatch SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">
# ["open-hatch", "SYSTEM", "http://www.textuality.com/boilerplate/OpenHatch.xml"]
# <!ENTITY open-hatch PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" "http://www.textuality.com/boilerplate/OpenHatch.xml">
# ["open-hatch", "PUBLIC", "-//Textuality//TEXT Standard open-hatch boilerplate//EN", "http://www.textuality.com/boilerplate/OpenHatch.xml"]
# <!ENTITY hatch-pic SYSTEM "../grafix/OpenHatch.gif" NDATA gif>
# ["hatch-pic", "SYSTEM", "../grafix/OpenHatch.gif", "NDATA", "gif"]
def entitydecl declaration
end
# <!NOTATION ...>
def notationdecl name, public_or_system, public_id, system_id
end
# Called when <![CDATA[ ... ]]> is encountered in a document.
# @p content "..."
def cdata content
end
# Called when an XML PI is encountered in the document.
# EG: <?xml version="1.0" encoding="utf"?>
# @p version the version attribute value. EG, "1.0"
# @p encoding the encoding attribute value, or nil. EG, "utf"
# @p standalone the standalone attribute value, or nil. EG, nil
# @p spaced the declaration is followed by a line break
def xmldecl version, encoding, standalone
end
# Called when a comment is encountered.
# @p comment The content of the comment
def comment comment
end
def progress position
end
end
end

Просмотреть файл

@ -1,28 +0,0 @@
# frozen_string_literal: false
module REXML
module Security
@@entity_expansion_limit = 10_000
# Set the entity expansion limit. By default the limit is set to 10000.
def self.entity_expansion_limit=( val )
@@entity_expansion_limit = val
end
# Get the entity expansion limit. By default the limit is set to 10000.
def self.entity_expansion_limit
return @@entity_expansion_limit
end
@@entity_expansion_text_limit = 10_240
# Set the entity expansion limit. By default the limit is set to 10240.
def self.entity_expansion_text_limit=( val )
@@entity_expansion_text_limit = val
end
# Get the entity expansion limit. By default the limit is set to 10240.
def self.entity_expansion_text_limit
return @@entity_expansion_text_limit
end
end
end

Просмотреть файл

@ -1,298 +0,0 @@
# coding: US-ASCII
# frozen_string_literal: false
require_relative 'encoding'
module REXML
# Generates Source-s. USE THIS CLASS.
class SourceFactory
# Generates a Source object
# @param arg Either a String, or an IO
# @return a Source, or nil if a bad argument was given
def SourceFactory::create_from(arg)
if arg.respond_to? :read and
arg.respond_to? :readline and
arg.respond_to? :nil? and
arg.respond_to? :eof?
IOSource.new(arg)
elsif arg.respond_to? :to_str
require 'stringio'
IOSource.new(StringIO.new(arg))
elsif arg.kind_of? Source
arg
else
raise "#{arg.class} is not a valid input stream. It must walk \n"+
"like either a String, an IO, or a Source."
end
end
end
# A Source can be searched for patterns, and wraps buffers and other
# objects and provides consumption of text
class Source
include Encoding
# The current buffer (what we're going to read next)
attr_reader :buffer
# The line number of the last consumed text
attr_reader :line
attr_reader :encoding
# Constructor
# @param arg must be a String, and should be a valid XML document
# @param encoding if non-null, sets the encoding of the source to this
# value, overriding all encoding detection
def initialize(arg, encoding=nil)
@orig = @buffer = arg
if encoding
self.encoding = encoding
else
detect_encoding
end
@line = 0
end
# Inherited from Encoding
# Overridden to support optimized en/decoding
def encoding=(enc)
return unless super
encoding_updated
end
# Scans the source for a given pattern. Note, that this is not your
# usual scan() method. For one thing, the pattern argument has some
# requirements; for another, the source can be consumed. You can easily
# confuse this method. Originally, the patterns were easier
# to construct and this method more robust, because this method
# generated search regexps on the fly; however, this was
# computationally expensive and slowed down the entire REXML package
# considerably, since this is by far the most commonly called method.
# @param pattern must be a Regexp, and must be in the form of
# /^\s*(#{your pattern, with no groups})(.*)/. The first group
# will be returned; the second group is used if the consume flag is
# set.
# @param consume if true, the pattern returned will be consumed, leaving
# everything after it in the Source.
# @return the pattern, if found, or nil if the Source is empty or the
# pattern is not found.
def scan(pattern, cons=false)
return nil if @buffer.nil?
rv = @buffer.scan(pattern)
@buffer = $' if cons and rv.size>0
rv
end
def read
end
def consume( pattern )
@buffer = $' if pattern.match( @buffer )
end
def match_to( char, pattern )
return pattern.match(@buffer)
end
def match_to_consume( char, pattern )
md = pattern.match(@buffer)
@buffer = $'
return md
end
def match(pattern, cons=false)
md = pattern.match(@buffer)
@buffer = $' if cons and md
return md
end
# @return true if the Source is exhausted
def empty?
@buffer == ""
end
def position
@orig.index( @buffer )
end
# @return the current line in the source
def current_line
lines = @orig.split
res = lines.grep @buffer[0..30]
res = res[-1] if res.kind_of? Array
lines.index( res ) if res
end
private
def detect_encoding
buffer_encoding = @buffer.encoding
detected_encoding = "UTF-8"
begin
@buffer.force_encoding("ASCII-8BIT")
if @buffer[0, 2] == "\xfe\xff"
@buffer[0, 2] = ""
detected_encoding = "UTF-16BE"
elsif @buffer[0, 2] == "\xff\xfe"
@buffer[0, 2] = ""
detected_encoding = "UTF-16LE"
elsif @buffer[0, 3] == "\xef\xbb\xbf"
@buffer[0, 3] = ""
detected_encoding = "UTF-8"
end
ensure
@buffer.force_encoding(buffer_encoding)
end
self.encoding = detected_encoding
end
def encoding_updated
if @encoding != 'UTF-8'
@buffer = decode(@buffer)
@to_utf = true
else
@to_utf = false
@buffer.force_encoding ::Encoding::UTF_8
end
end
end
# A Source that wraps an IO. See the Source class for method
# documentation
class IOSource < Source
#attr_reader :block_size
# block_size has been deprecated
def initialize(arg, block_size=500, encoding=nil)
@er_source = @source = arg
@to_utf = false
@pending_buffer = nil
if encoding
super("", encoding)
else
super(@source.read(3) || "")
end
if !@to_utf and
@buffer.respond_to?(:force_encoding) and
@source.respond_to?(:external_encoding) and
@source.external_encoding != ::Encoding::UTF_8
@force_utf8 = true
else
@force_utf8 = false
end
end
def scan(pattern, cons=false)
rv = super
# You'll notice that this next section is very similar to the same
# section in match(), but just a liiittle different. This is
# because it is a touch faster to do it this way with scan()
# than the way match() does it; enough faster to warrant duplicating
# some code
if rv.size == 0
until @buffer =~ pattern or @source.nil?
begin
@buffer << readline
rescue Iconv::IllegalSequence
raise
rescue
@source = nil
end
end
rv = super
end
rv.taint if RUBY_VERSION < '2.7'
rv
end
def read
begin
@buffer << readline
rescue Exception, NameError
@source = nil
end
end
def consume( pattern )
match( pattern, true )
end
def match( pattern, cons=false )
rv = pattern.match(@buffer)
@buffer = $' if cons and rv
while !rv and @source
begin
@buffer << readline
rv = pattern.match(@buffer)
@buffer = $' if cons and rv
rescue
@source = nil
end
end
rv.taint if RUBY_VERSION < '2.7'
rv
end
def empty?
super and ( @source.nil? || @source.eof? )
end
def position
@er_source.pos rescue 0
end
# @return the current line in the source
def current_line
begin
pos = @er_source.pos # The byte position in the source
lineno = @er_source.lineno # The XML < position in the source
@er_source.rewind
line = 0 # The \r\n position in the source
begin
while @er_source.pos < pos
@er_source.readline
line += 1
end
rescue
end
@er_source.seek(pos)
rescue IOError
pos = -1
line = -1
end
[pos, lineno, line]
end
private
def readline
str = @source.readline(@line_break)
if @pending_buffer
if str.nil?
str = @pending_buffer
else
str = @pending_buffer + str
end
@pending_buffer = nil
end
return nil if str.nil?
if @to_utf
decode(str)
else
str.force_encoding(::Encoding::UTF_8) if @force_utf8
str
end
end
def encoding_updated
case @encoding
when "UTF-16BE", "UTF-16LE"
@source.binmode
@source.set_encoding(@encoding, @encoding)
end
@line_break = encode(">")
@pending_buffer, @buffer = @buffer, ""
@pending_buffer.force_encoding(@encoding)
super
end
end
end

Просмотреть файл

@ -1,93 +0,0 @@
# frozen_string_literal: false
module REXML
# A template for stream parser listeners.
# Note that the declarations (attlistdecl, elementdecl, etc) are trivially
# processed; REXML doesn't yet handle doctype entity declarations, so you
# have to parse them out yourself.
module StreamListener
# Called when a tag is encountered.
# @p name the tag name
# @p attrs an array of arrays of attribute/value pairs, suitable for
# use with assoc or rassoc. IE, <tag attr1="value1" attr2="value2">
# will result in
# tag_start( "tag", # [["attr1","value1"],["attr2","value2"]])
def tag_start name, attrs
end
# Called when the end tag is reached. In the case of <tag/>, tag_end
# will be called immediately after tag_start
# @p the name of the tag
def tag_end name
end
# Called when text is encountered in the document
# @p text the text content.
def text text
end
# Called when an instruction is encountered. EG: <?xsl sheet='foo'?>
# @p name the instruction name; in the example, "xsl"
# @p instruction the rest of the instruction. In the example,
# "sheet='foo'"
def instruction name, instruction
end
# Called when a comment is encountered.
# @p comment The content of the comment
def comment comment
end
# Handles a doctype declaration. Any attributes of the doctype which are
# not supplied will be nil. # EG, <!DOCTYPE me PUBLIC "foo" "bar">
# @p name the name of the doctype; EG, "me"
# @p pub_sys "PUBLIC", "SYSTEM", or nil. EG, "PUBLIC"
# @p long_name the supplied long name, or nil. EG, "foo"
# @p uri the uri of the doctype, or nil. EG, "bar"
def doctype name, pub_sys, long_name, uri
end
# Called when the doctype is done
def doctype_end
end
# If a doctype includes an ATTLIST declaration, it will cause this
# method to be called. The content is the declaration itself, unparsed.
# EG, <!ATTLIST el attr CDATA #REQUIRED> will come to this method as "el
# attr CDATA #REQUIRED". This is the same for all of the .*decl
# methods.
def attlistdecl element_name, attributes, raw_content
end
# <!ELEMENT ...>
def elementdecl content
end
# <!ENTITY ...>
# The argument passed to this method is an array of the entity
# declaration. It can be in a number of formats, but in general it
# returns (example, result):
# <!ENTITY % YN '"Yes"'>
# ["YN", "\"Yes\"", "%"]
# <!ENTITY % YN 'Yes'>
# ["YN", "Yes", "%"]
# <!ENTITY WhatHeSaid "He said %YN;">
# ["WhatHeSaid", "He said %YN;"]
# <!ENTITY open-hatch SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">
# ["open-hatch", "SYSTEM", "http://www.textuality.com/boilerplate/OpenHatch.xml"]
# <!ENTITY open-hatch PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" "http://www.textuality.com/boilerplate/OpenHatch.xml">
# ["open-hatch", "PUBLIC", "-//Textuality//TEXT Standard open-hatch boilerplate//EN", "http://www.textuality.com/boilerplate/OpenHatch.xml"]
# <!ENTITY hatch-pic SYSTEM "../grafix/OpenHatch.gif" NDATA gif>
# ["hatch-pic", "SYSTEM", "../grafix/OpenHatch.gif", "gif"]
def entitydecl content
end
# <!NOTATION ...>
def notationdecl content
end
# Called when %foo; is encountered in a doctype declaration.
# @p content "foo"
def entity content
end
# Called when <![CDATA[ ... ]]> is encountered in a document.
# @p content "..."
def cdata content
end
# Called when an XML PI is encountered in the document.
# EG: <?xml version="1.0" encoding="utf"?>
# @p version the version attribute value. EG, "1.0"
# @p encoding the encoding attribute value, or nil. EG, "utf"
# @p standalone the standalone attribute value, or nil. EG, nil
def xmldecl version, encoding, standalone
end
end
end

Просмотреть файл

@ -1,424 +0,0 @@
# frozen_string_literal: false
require_relative 'security'
require_relative 'entity'
require_relative 'doctype'
require_relative 'child'
require_relative 'doctype'
require_relative 'parseexception'
module REXML
# Represents text nodes in an XML document
class Text < Child
include Comparable
# The order in which the substitutions occur
SPECIALS = [ /&(?!#?[\w-]+;)/u, /</u, />/u, /"/u, /'/u, /\r/u ]
SUBSTITUTES = ['&amp;', '&lt;', '&gt;', '&quot;', '&apos;', '&#13;']
# Characters which are substituted in written strings
SLAICEPS = [ '<', '>', '"', "'", '&' ]
SETUTITSBUS = [ /&lt;/u, /&gt;/u, /&quot;/u, /&apos;/u, /&amp;/u ]
# If +raw+ is true, then REXML leaves the value alone
attr_accessor :raw
NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
NUMERICENTITY = /&#0*((?:\d+)|(?:x[a-fA-F0-9]+));/
VALID_CHAR = [
0x9, 0xA, 0xD,
(0x20..0xD7FF),
(0xE000..0xFFFD),
(0x10000..0x10FFFF)
]
if String.method_defined? :encode
VALID_XML_CHARS = Regexp.new('^['+
VALID_CHAR.map { |item|
case item
when Integer
[item].pack('U').force_encoding('utf-8')
when Range
[item.first, '-'.ord, item.last].pack('UUU').force_encoding('utf-8')
end
}.join +
']*$')
else
VALID_XML_CHARS = /^(
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE][\x80-\xBF]{2} # straight 3-byte
| \xEF[\x80-\xBE]{2} #
| \xEF\xBF[\x80-\xBD] # excluding U+fffe and U+ffff
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$/nx;
end
# Constructor
# +arg+ if a String, the content is set to the String. If a Text,
# the object is shallowly cloned.
#
# +respect_whitespace+ (boolean, false) if true, whitespace is
# respected
#
# +parent+ (nil) if this is a Parent object, the parent
# will be set to this.
#
# +raw+ (nil) This argument can be given three values.
# If true, then the value of used to construct this object is expected to
# contain no unescaped XML markup, and REXML will not change the text. If
# this value is false, the string may contain any characters, and REXML will
# escape any and all defined entities whose values are contained in the
# text. If this value is nil (the default), then the raw value of the
# parent will be used as the raw value for this node. If there is no raw
# value for the parent, and no value is supplied, the default is false.
# Use this field if you have entities defined for some text, and you don't
# want REXML to escape that text in output.
# Text.new( "<&", false, nil, false ) #-> "&lt;&amp;"
# Text.new( "&lt;&amp;", false, nil, false ) #-> "&amp;lt;&amp;amp;"
# Text.new( "<&", false, nil, true ) #-> Parse exception
# Text.new( "&lt;&amp;", false, nil, true ) #-> "&lt;&amp;"
# # Assume that the entity "s" is defined to be "sean"
# # and that the entity "r" is defined to be "russell"
# Text.new( "sean russell" ) #-> "&s; &r;"
# Text.new( "sean russell", false, nil, true ) #-> "sean russell"
#
# +entity_filter+ (nil) This can be an array of entities to match in the
# supplied text. This argument is only useful if +raw+ is set to false.
# Text.new( "sean russell", false, nil, false, ["s"] ) #-> "&s; russell"
# Text.new( "sean russell", false, nil, true, ["s"] ) #-> "sean russell"
# In the last example, the +entity_filter+ argument is ignored.
#
# +illegal+ INTERNAL USE ONLY
def initialize(arg, respect_whitespace=false, parent=nil, raw=nil,
entity_filter=nil, illegal=NEEDS_A_SECOND_CHECK )
@raw = false
@parent = nil
@entity_filter = nil
if parent
super( parent )
@raw = parent.raw
end
if arg.kind_of? String
@string = arg.dup
elsif arg.kind_of? Text
@string = arg.instance_variable_get(:@string).dup
@raw = arg.raw
@entity_filter = arg.instance_variable_get(:@entity_filter)
else
raise "Illegal argument of type #{arg.type} for Text constructor (#{arg})"
end
@string.squeeze!(" \n\t") unless respect_whitespace
@string.gsub!(/\r\n?/, "\n")
@raw = raw unless raw.nil?
@entity_filter = entity_filter if entity_filter
clear_cache
Text.check(@string, illegal, doctype) if @raw
end
def parent= parent
super(parent)
Text.check(@string, NEEDS_A_SECOND_CHECK, doctype) if @raw and @parent
end
# check for illegal characters
def Text.check string, pattern, doctype
# illegal anywhere
if string !~ VALID_XML_CHARS
if String.method_defined? :encode
string.chars.each do |c|
case c.ord
when *VALID_CHAR
else
raise "Illegal character #{c.inspect} in raw string #{string.inspect}"
end
end
else
string.scan(/[\x00-\x7F]|[\x80-\xBF][\xC0-\xF0]*|[\xC0-\xF0]/n) do |c|
case c.unpack('U')
when *VALID_CHAR
else
raise "Illegal character #{c.inspect} in raw string #{string.inspect}"
end
end
end
end
# context sensitive
string.scan(pattern) do
if $1[-1] != ?;
raise "Illegal character #{$1.inspect} in raw string #{string.inspect}"
elsif $1[0] == ?&
if $5 and $5[0] == ?#
case ($5[1] == ?x ? $5[2..-1].to_i(16) : $5[1..-1].to_i)
when *VALID_CHAR
else
raise "Illegal character #{$1.inspect} in raw string #{string.inspect}"
end
# FIXME: below can't work but this needs API change.
# elsif @parent and $3 and !SUBSTITUTES.include?($1)
# if !doctype or !doctype.entities.has_key?($3)
# raise "Undeclared entity '#{$1}' in raw string \"#{string}\""
# end
end
end
end
end
def node_type
:text
end
def empty?
@string.size==0
end
def clone
return Text.new(self, true)
end
# Appends text to this text node. The text is appended in the +raw+ mode
# of this text node.
#
# +returns+ the text itself to enable method chain like
# 'text << "XXX" << "YYY"'.
def <<( to_append )
@string << to_append.gsub( /\r\n?/, "\n" )
clear_cache
self
end
# +other+ a String or a Text
# +returns+ the result of (to_s <=> arg.to_s)
def <=>( other )
to_s() <=> other.to_s
end
def doctype
if @parent
doc = @parent.document
doc.doctype if doc
end
end
REFERENCE = /#{Entity::REFERENCE}/
# Returns the string value of this text node. This string is always
# escaped, meaning that it is a valid XML text node string, and all
# entities that can be escaped, have been inserted. This method respects
# the entity filter set in the constructor.
#
# # Assume that the entity "s" is defined to be "sean", and that the
# # entity "r" is defined to be "russell"
# t = Text.new( "< & sean russell", false, nil, false, ['s'] )
# t.to_s #-> "&lt; &amp; &s; russell"
# t = Text.new( "< & &s; russell", false, nil, false )
# t.to_s #-> "&lt; &amp; &s; russell"
# u = Text.new( "sean russell", false, nil, true )
# u.to_s #-> "sean russell"
def to_s
return @string if @raw
@normalized ||= Text::normalize( @string, doctype, @entity_filter )
end
def inspect
@string.inspect
end
# Returns the string value of this text. This is the text without
# entities, as it might be used programmatically, or printed to the
# console. This ignores the 'raw' attribute setting, and any
# entity_filter.
#
# # Assume that the entity "s" is defined to be "sean", and that the
# # entity "r" is defined to be "russell"
# t = Text.new( "< & sean russell", false, nil, false, ['s'] )
# t.value #-> "< & sean russell"
# t = Text.new( "< & &s; russell", false, nil, false )
# t.value #-> "< & sean russell"
# u = Text.new( "sean russell", false, nil, true )
# u.value #-> "sean russell"
def value
@unnormalized ||= Text::unnormalize( @string, doctype )
end
# Sets the contents of this text node. This expects the text to be
# unnormalized. It returns self.
#
# e = Element.new( "a" )
# e.add_text( "foo" ) # <a>foo</a>
# e[0].value = "bar" # <a>bar</a>
# e[0].value = "<a>" # <a>&lt;a&gt;</a>
def value=( val )
@string = val.gsub( /\r\n?/, "\n" )
clear_cache
@raw = false
end
def wrap(string, width, addnewline=false)
# Recursively wrap string at width.
return string if string.length <= width
place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
if addnewline then
return "\n" + string[0,place] + "\n" + wrap(string[place+1..-1], width)
else
return string[0,place] + "\n" + wrap(string[place+1..-1], width)
end
end
def indent_text(string, level=1, style="\t", indentfirstline=true)
return string if level < 0
new_string = ''
string.each_line { |line|
indent_string = style * level
new_line = (indent_string + line).sub(/[\s]+$/,'')
new_string << new_line
}
new_string.strip! unless indentfirstline
return new_string
end
# == DEPRECATED
# See REXML::Formatters
#
def write( writer, indent=-1, transitive=false, ie_hack=false )
Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters", uplevel: 1)
formatter = if indent > -1
REXML::Formatters::Pretty.new( indent )
else
REXML::Formatters::Default.new
end
formatter.write( self, writer )
end
# FIXME
# This probably won't work properly
def xpath
path = @parent.xpath
path += "/text()"
return path
end
# Writes out text, substituting special characters beforehand.
# +out+ A String, IO, or any other object supporting <<( String )
# +input+ the text to substitute and the write out
#
# z=utf8.unpack("U*")
# ascOut=""
# z.each{|r|
# if r < 0x100
# ascOut.concat(r.chr)
# else
# ascOut.concat(sprintf("&#x%x;", r))
# end
# }
# puts ascOut
def write_with_substitution out, input
copy = input.clone
# Doing it like this rather than in a loop improves the speed
copy.gsub!( SPECIALS[0], SUBSTITUTES[0] )
copy.gsub!( SPECIALS[1], SUBSTITUTES[1] )
copy.gsub!( SPECIALS[2], SUBSTITUTES[2] )
copy.gsub!( SPECIALS[3], SUBSTITUTES[3] )
copy.gsub!( SPECIALS[4], SUBSTITUTES[4] )
copy.gsub!( SPECIALS[5], SUBSTITUTES[5] )
out << copy
end
private
def clear_cache
@normalized = nil
@unnormalized = nil
end
# Reads text, substituting entities
def Text::read_with_substitution( input, illegal=nil )
copy = input.clone
if copy =~ illegal
raise ParseException.new( "malformed text: Illegal character #$& in \"#{copy}\"" )
end if illegal
copy.gsub!( /\r\n?/, "\n" )
if copy.include? ?&
copy.gsub!( SETUTITSBUS[0], SLAICEPS[0] )
copy.gsub!( SETUTITSBUS[1], SLAICEPS[1] )
copy.gsub!( SETUTITSBUS[2], SLAICEPS[2] )
copy.gsub!( SETUTITSBUS[3], SLAICEPS[3] )
copy.gsub!( SETUTITSBUS[4], SLAICEPS[4] )
copy.gsub!( /&#0*((?:\d+)|(?:x[a-f0-9]+));/ ) {
m=$1
#m='0' if m==''
m = "0#{m}" if m[0] == ?x
[Integer(m)].pack('U*')
}
end
copy
end
EREFERENCE = /&(?!#{Entity::NAME};)/
# Escapes all possible entities
def Text::normalize( input, doctype=nil, entity_filter=nil )
copy = input.to_s
# Doing it like this rather than in a loop improves the speed
#copy = copy.gsub( EREFERENCE, '&amp;' )
copy = copy.gsub( "&", "&amp;" )
if doctype
# Replace all ampersands that aren't part of an entity
doctype.entities.each_value do |entity|
copy = copy.gsub( entity.value,
"&#{entity.name};" ) if entity.value and
not( entity_filter and entity_filter.include?(entity.name) )
end
else
# Replace all ampersands that aren't part of an entity
DocType::DEFAULT_ENTITIES.each_value do |entity|
copy = copy.gsub(entity.value, "&#{entity.name};" )
end
end
copy
end
# Unescapes all possible entities
def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil )
sum = 0
string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) {
s = Text.expand($&, doctype, filter)
if sum + s.bytesize > Security.entity_expansion_text_limit
raise "entity expansion has grown too large"
else
sum += s.bytesize
end
s
}
end
def Text.expand(ref, doctype, filter)
if ref[1] == ?#
if ref[2] == ?x
[ref[3...-1].to_i(16)].pack('U*')
else
[ref[2...-1].to_i].pack('U*')
end
elsif ref == '&amp;'
'&'
elsif filter and filter.include?( ref[1...-1] )
ref
elsif doctype
doctype.entity( ref[1...-1] ) or ref
else
entity_value = DocType::DEFAULT_ENTITIES[ ref[1...-1] ]
entity_value ? entity_value.value : ref
end
end
end
end

Просмотреть файл

@ -1,9 +0,0 @@
# frozen_string_literal: false
require_relative 'parseexception'
module REXML
class UndefinedNamespaceException < ParseException
def initialize( prefix, source, parser )
super( "Undefined prefix #{prefix} found" )
end
end
end

Просмотреть файл

@ -1,539 +0,0 @@
# frozen_string_literal: false
require_relative "validation"
require_relative "../parsers/baseparser"
module REXML
module Validation
# Implemented:
# * empty
# * element
# * attribute
# * text
# * optional
# * choice
# * oneOrMore
# * zeroOrMore
# * group
# * value
# * interleave
# * mixed
# * ref
# * grammar
# * start
# * define
#
# Not implemented:
# * data
# * param
# * include
# * externalRef
# * notAllowed
# * anyName
# * nsName
# * except
# * name
class RelaxNG
include Validator
INFINITY = 1.0 / 0.0
EMPTY = Event.new( nil )
TEXT = [:start_element, "text"]
attr_accessor :current
attr_accessor :count
attr_reader :references
# FIXME: Namespaces
def initialize source
parser = REXML::Parsers::BaseParser.new( source )
@count = 0
@references = {}
@root = @current = Sequence.new(self)
@root.previous = true
states = [ @current ]
begin
event = parser.pull
case event[0]
when :start_element
case event[1]
when "empty"
when "element", "attribute", "text", "value"
states[-1] << event
when "optional"
states << Optional.new( self )
states[-2] << states[-1]
when "choice"
states << Choice.new( self )
states[-2] << states[-1]
when "oneOrMore"
states << OneOrMore.new( self )
states[-2] << states[-1]
when "zeroOrMore"
states << ZeroOrMore.new( self )
states[-2] << states[-1]
when "group"
states << Sequence.new( self )
states[-2] << states[-1]
when "interleave"
states << Interleave.new( self )
states[-2] << states[-1]
when "mixed"
states << Interleave.new( self )
states[-2] << states[-1]
states[-1] << TEXT
when "define"
states << [ event[2]["name"] ]
when "ref"
states[-1] << Ref.new( event[2]["name"] )
when "anyName"
states << AnyName.new( self )
states[-2] << states[-1]
when "nsName"
when "except"
when "name"
when "data"
when "param"
when "include"
when "grammar"
when "start"
when "externalRef"
when "notAllowed"
end
when :end_element
case event[1]
when "element", "attribute"
states[-1] << event
when "zeroOrMore", "oneOrMore", "choice", "optional",
"interleave", "group", "mixed"
states.pop
when "define"
ref = states.pop
@references[ ref.shift ] = ref
#when "empty"
end
when :end_document
states[-1] << event
when :text
states[-1] << event
end
end while event[0] != :end_document
end
def receive event
validate( event )
end
end
class State
def initialize( context )
@previous = []
@events = []
@current = 0
@count = context.count += 1
@references = context.references
@value = false
end
def reset
return if @current == 0
@current = 0
@events.each {|s| s.reset if s.kind_of? State }
end
def previous=( previous )
@previous << previous
end
def next( event )
#print "In next with #{event.inspect}. "
#p @previous
return @previous.pop.next( event ) if @events[@current].nil?
expand_ref_in( @events, @current ) if @events[@current].class == Ref
if ( @events[@current].kind_of? State )
@current += 1
@events[@current-1].previous = self
return @events[@current-1].next( event )
end
if ( @events[@current].matches?(event) )
@current += 1
if @events[@current].nil?
return @previous.pop
elsif @events[@current].kind_of? State
@current += 1
@events[@current-1].previous = self
return @events[@current-1]
else
return self
end
else
return nil
end
end
def to_s
# Abbreviated:
self.class.name =~ /(?:::)(\w)\w+$/
# Full:
#self.class.name =~ /(?:::)(\w+)$/
"#$1.#@count"
end
def inspect
"< #{to_s} #{@events.collect{|e|
pre = e == @events[@current] ? '#' : ''
pre + e.inspect unless self == e
}.join(', ')} >"
end
def expected
return [@events[@current]]
end
def <<( event )
add_event_to_arry( @events, event )
end
protected
def expand_ref_in( arry, ind )
new_events = []
@references[ arry[ind].to_s ].each{ |evt|
add_event_to_arry(new_events,evt)
}
arry[ind,1] = new_events
end
def add_event_to_arry( arry, evt )
evt = generate_event( evt )
if evt.kind_of? String
arry[-1].event_arg = evt if arry[-1].kind_of? Event and @value
@value = false
else
arry << evt
end
end
def generate_event( event )
return event if event.kind_of? State or event.class == Ref
evt = nil
arg = nil
case event[0]
when :start_element
case event[1]
when "element"
evt = :start_element
arg = event[2]["name"]
when "attribute"
evt = :start_attribute
arg = event[2]["name"]
when "text"
evt = :text
when "value"
evt = :text
@value = true
end
when :text
return event[1]
when :end_document
return Event.new( event[0] )
else # then :end_element
case event[1]
when "element"
evt = :end_element
when "attribute"
evt = :end_attribute
end
end
return Event.new( evt, arg )
end
end
class Sequence < State
def matches?(event)
@events[@current].matches?( event )
end
end
class Optional < State
def next( event )
if @current == 0
rv = super
return rv if rv
@prior = @previous.pop
return @prior.next( event )
end
super
end
def matches?(event)
@events[@current].matches?(event) ||
(@current == 0 and @previous[-1].matches?(event))
end
def expected
return [ @prior.expected, @events[0] ].flatten if @current == 0
return [@events[@current]]
end
end
class ZeroOrMore < Optional
def next( event )
expand_ref_in( @events, @current ) if @events[@current].class == Ref
if ( @events[@current].matches?(event) )
@current += 1
if @events[@current].nil?
@current = 0
return self
elsif @events[@current].kind_of? State
@current += 1
@events[@current-1].previous = self
return @events[@current-1]
else
return self
end
else
@prior = @previous.pop
return @prior.next( event ) if @current == 0
return nil
end
end
def expected
return [ @prior.expected, @events[0] ].flatten if @current == 0
return [@events[@current]]
end
end
class OneOrMore < State
def initialize context
super
@ord = 0
end
def reset
super
@ord = 0
end
def next( event )
expand_ref_in( @events, @current ) if @events[@current].class == Ref
if ( @events[@current].matches?(event) )
@current += 1
@ord += 1
if @events[@current].nil?
@current = 0
return self
elsif @events[@current].kind_of? State
@current += 1
@events[@current-1].previous = self
return @events[@current-1]
else
return self
end
else
return @previous.pop.next( event ) if @current == 0 and @ord > 0
return nil
end
end
def matches?( event )
@events[@current].matches?(event) ||
(@current == 0 and @ord > 0 and @previous[-1].matches?(event))
end
def expected
if @current == 0 and @ord > 0
return [@previous[-1].expected, @events[0]].flatten
else
return [@events[@current]]
end
end
end
class Choice < State
def initialize context
super
@choices = []
end
def reset
super
@events = []
@choices.each { |c| c.each { |s| s.reset if s.kind_of? State } }
end
def <<( event )
add_event_to_arry( @choices, event )
end
def next( event )
# Make the choice if we haven't
if @events.size == 0
c = 0 ; max = @choices.size
while c < max
if @choices[c][0].class == Ref
expand_ref_in( @choices[c], 0 )
@choices += @choices[c]
@choices.delete( @choices[c] )
max -= 1
else
c += 1
end
end
@events = @choices.find { |evt| evt[0].matches? event }
# Remove the references
# Find the events
end
unless @events
@events = []
return nil
end
super
end
def matches?( event )
return @events[@current].matches?( event ) if @events.size > 0
!@choices.find{|evt| evt[0].matches?(event)}.nil?
end
def expected
return [@events[@current]] if @events.size > 0
return @choices.collect do |x|
if x[0].kind_of? State
x[0].expected
else
x[0]
end
end.flatten
end
def inspect
"< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' or ')} >"
end
protected
def add_event_to_arry( arry, evt )
if evt.kind_of? State or evt.class == Ref
arry << [evt]
elsif evt[0] == :text
if arry[-1] and
arry[-1][-1].kind_of?( Event ) and
arry[-1][-1].event_type == :text and @value
arry[-1][-1].event_arg = evt[1]
@value = false
end
else
arry << [] if evt[0] == :start_element
arry[-1] << generate_event( evt )
end
end
end
class Interleave < Choice
def initialize context
super
@choice = 0
end
def reset
@choice = 0
end
def next_current( event )
# Expand references
c = 0 ; max = @choices.size
while c < max
if @choices[c][0].class == Ref
expand_ref_in( @choices[c], 0 )
@choices += @choices[c]
@choices.delete( @choices[c] )
max -= 1
else
c += 1
end
end
@events = @choices[@choice..-1].find { |evt| evt[0].matches? event }
@current = 0
if @events
# reorder the choices
old = @choices[@choice]
idx = @choices.index( @events )
@choices[@choice] = @events
@choices[idx] = old
@choice += 1
end
@events = [] unless @events
end
def next( event )
# Find the next series
next_current(event) unless @events[@current]
return nil unless @events[@current]
expand_ref_in( @events, @current ) if @events[@current].class == Ref
if ( @events[@current].kind_of? State )
@current += 1
@events[@current-1].previous = self
return @events[@current-1].next( event )
end
return @previous.pop.next( event ) if @events[@current].nil?
if ( @events[@current].matches?(event) )
@current += 1
if @events[@current].nil?
return self unless @choices[@choice].nil?
return @previous.pop
elsif @events[@current].kind_of? State
@current += 1
@events[@current-1].previous = self
return @events[@current-1]
else
return self
end
else
return nil
end
end
def matches?( event )
return @events[@current].matches?( event ) if @events[@current]
!@choices[@choice..-1].find{|evt| evt[0].matches?(event)}.nil?
end
def expected
return [@events[@current]] if @events[@current]
return @choices[@choice..-1].collect do |x|
if x[0].kind_of? State
x[0].expected
else
x[0]
end
end.flatten
end
def inspect
"< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' and ')} >"
end
end
class Ref
def initialize value
@value = value
end
def to_s
@value
end
def inspect
"{#{to_s}}"
end
end
end
end

Просмотреть файл

@ -1,144 +0,0 @@
# frozen_string_literal: false
require_relative 'validationexception'
module REXML
module Validation
module Validator
NILEVENT = [ nil ]
def reset
@current = @root
@root.reset
@root.previous = true
@attr_stack = []
self
end
def dump
puts @root.inspect
end
def validate( event )
@attr_stack = [] unless defined? @attr_stack
match = @current.next(event)
raise ValidationException.new( "Validation error. Expected: "+
@current.expected.join( " or " )+" from #{@current.inspect} "+
" but got #{Event.new( event[0], event[1] ).inspect}" ) unless match
@current = match
# Check for attributes
case event[0]
when :start_element
@attr_stack << event[2]
begin
sattr = [:start_attribute, nil]
eattr = [:end_attribute]
text = [:text, nil]
k, = event[2].find { |key,value|
sattr[1] = key
m = @current.next( sattr )
if m
# If the state has text children...
if m.matches?( eattr )
@current = m
else
text[1] = value
m = m.next( text )
text[1] = nil
return false unless m
@current = m if m
end
m = @current.next( eattr )
if m
@current = m
true
else
false
end
else
false
end
}
event[2].delete(k) if k
end while k
when :end_element
attrs = @attr_stack.pop
raise ValidationException.new( "Validation error. Illegal "+
" attributes: #{attrs.inspect}") if attrs.length > 0
end
end
end
class Event
def initialize(event_type, event_arg=nil )
@event_type = event_type
@event_arg = event_arg
end
attr_reader :event_type
attr_accessor :event_arg
def done?
@done
end
def single?
return (@event_type != :start_element and @event_type != :start_attribute)
end
def matches?( event )
return false unless event[0] == @event_type
case event[0]
when nil
return true
when :start_element
return true if event[1] == @event_arg
when :end_element
return true
when :start_attribute
return true if event[1] == @event_arg
when :end_attribute
return true
when :end_document
return true
when :text
return (@event_arg.nil? or @event_arg == event[1])
=begin
when :processing_instruction
false
when :xmldecl
false
when :start_doctype
false
when :end_doctype
false
when :externalentity
false
when :elementdecl
false
when :entity
false
when :attlistdecl
false
when :notationdecl
false
when :end_doctype
false
=end
else
false
end
end
def ==( other )
return false unless other.kind_of? Event
@event_type == other.event_type and @event_arg == other.event_arg
end
def to_s
inspect
end
def inspect
"#{@event_type.inspect}( #@event_arg )"
end
end
end
end

Просмотреть файл

@ -1,10 +0,0 @@
# frozen_string_literal: false
module REXML
module Validation
class ValidationException < RuntimeError
def initialize msg
super
end
end
end
end

Просмотреть файл

@ -1,130 +0,0 @@
# frozen_string_literal: false
require_relative 'encoding'
require_relative 'source'
module REXML
# NEEDS DOCUMENTATION
class XMLDecl < Child
include Encoding
DEFAULT_VERSION = "1.0"
DEFAULT_ENCODING = "UTF-8"
DEFAULT_STANDALONE = "no"
START = "<?xml"
STOP = "?>"
attr_accessor :version, :standalone
attr_reader :writeencoding, :writethis
def initialize(version=DEFAULT_VERSION, encoding=nil, standalone=nil)
@writethis = true
@writeencoding = !encoding.nil?
if version.kind_of? XMLDecl
super()
@version = version.version
self.encoding = version.encoding
@writeencoding = version.writeencoding
@standalone = version.standalone
@writethis = version.writethis
else
super()
@version = version
self.encoding = encoding
@standalone = standalone
end
@version = DEFAULT_VERSION if @version.nil?
end
def clone
XMLDecl.new(self)
end
# indent::
# Ignored. There must be no whitespace before an XML declaration
# transitive::
# Ignored
# ie_hack::
# Ignored
def write(writer, indent=-1, transitive=false, ie_hack=false)
return nil unless @writethis or writer.kind_of? Output
writer << START
writer << " #{content encoding}"
writer << STOP
end
def ==( other )
other.kind_of?(XMLDecl) and
other.version == @version and
other.encoding == self.encoding and
other.standalone == @standalone
end
def xmldecl version, encoding, standalone
@version = version
self.encoding = encoding
@standalone = standalone
end
def node_type
:xmldecl
end
alias :stand_alone? :standalone
alias :old_enc= :encoding=
def encoding=( enc )
if enc.nil?
self.old_enc = "UTF-8"
@writeencoding = false
else
self.old_enc = enc
@writeencoding = true
end
self.dowrite
end
# Only use this if you do not want the XML declaration to be written;
# this object is ignored by the XML writer. Otherwise, instantiate your
# own XMLDecl and add it to the document.
#
# Note that XML 1.1 documents *must* include an XML declaration
def XMLDecl.default
rv = XMLDecl.new( "1.0" )
rv.nowrite
rv
end
def nowrite
@writethis = false
end
def dowrite
@writethis = true
end
def inspect
"#{START} ... #{STOP}"
end
private
def content(enc)
context = nil
context = parent.context if parent
if context and context[:prologue_quote] == :quote
quote = "\""
else
quote = "'"
end
rv = "version=#{quote}#{@version}#{quote}"
if @writeencoding or enc !~ /\Autf-8\z/i
rv << " encoding=#{quote}#{enc}#{quote}"
end
if @standalone
rv << " standalone=#{quote}#{@standalone}#{quote}"
end
rv
end
end
end

Просмотреть файл

@ -1,85 +0,0 @@
# frozen_string_literal: false
module REXML
# Defines a number of tokens used for parsing XML. Not for general
# consumption.
module XMLTokens
# From http://www.w3.org/TR/REC-xml/#sec-common-syn
#
# [4] NameStartChar ::=
# ":" |
# [A-Z] |
# "_" |
# [a-z] |
# [#xC0-#xD6] |
# [#xD8-#xF6] |
# [#xF8-#x2FF] |
# [#x370-#x37D] |
# [#x37F-#x1FFF] |
# [#x200C-#x200D] |
# [#x2070-#x218F] |
# [#x2C00-#x2FEF] |
# [#x3001-#xD7FF] |
# [#xF900-#xFDCF] |
# [#xFDF0-#xFFFD] |
# [#x10000-#xEFFFF]
name_start_chars = [
":",
"A-Z",
"_",
"a-z",
"\\u00C0-\\u00D6",
"\\u00D8-\\u00F6",
"\\u00F8-\\u02FF",
"\\u0370-\\u037D",
"\\u037F-\\u1FFF",
"\\u200C-\\u200D",
"\\u2070-\\u218F",
"\\u2C00-\\u2FEF",
"\\u3001-\\uD7FF",
"\\uF900-\\uFDCF",
"\\uFDF0-\\uFFFD",
"\\u{10000}-\\u{EFFFF}",
]
# From http://www.w3.org/TR/REC-xml/#sec-common-syn
#
# [4a] NameChar ::=
# NameStartChar |
# "-" |
# "." |
# [0-9] |
# #xB7 |
# [#x0300-#x036F] |
# [#x203F-#x2040]
name_chars = name_start_chars + [
"\\-",
"\\.",
"0-9",
"\\u00B7",
"\\u0300-\\u036F",
"\\u203F-\\u2040",
]
NAME_START_CHAR = "[#{name_start_chars.join('')}]"
NAME_CHAR = "[#{name_chars.join('')}]"
NAMECHAR = NAME_CHAR # deprecated. Use NAME_CHAR instead.
# From http://www.w3.org/TR/xml-names11/#NT-NCName
#
# [6] NCNameStartChar ::= NameStartChar - ':'
ncname_start_chars = name_start_chars - [":"]
# From http://www.w3.org/TR/xml-names11/#NT-NCName
#
# [5] NCNameChar ::= NameChar - ':'
ncname_chars = name_chars - [":"]
NCNAME_STR = "[#{ncname_start_chars.join('')}][#{ncname_chars.join('')}]*"
NAME_STR = "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
NAME = "(#{NAME_START_CHAR}#{NAME_CHAR}*)"
NMTOKEN = "(?:#{NAME_CHAR})+"
NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*"
REFERENCE = "(?:&#{NAME};|&#\\d+;|&#x[0-9a-fA-F]+;)"
#REFERENCE = "(?:#{ENTITYREF}|#{CHARREF})"
#ENTITYREF = "&#{NAME};"
#CHARREF = "&#\\d+;|&#x[0-9a-fA-F]+;"
end
end

Просмотреть файл

@ -1,81 +0,0 @@
# frozen_string_literal: false
require_relative 'functions'
require_relative 'xpath_parser'
module REXML
# Wrapper class. Use this class to access the XPath functions.
class XPath
include Functions
# A base Hash object, supposing to be used when initializing a
# default empty namespaces set, but is currently unused.
# TODO: either set the namespaces=EMPTY_HASH, or deprecate this.
EMPTY_HASH = {}
# Finds and returns the first node that matches the supplied xpath.
# element::
# The context element
# path::
# The xpath to search for. If not supplied or nil, returns the first
# node matching '*'.
# namespaces::
# If supplied, a Hash which defines a namespace mapping.
# variables::
# If supplied, a Hash which maps $variables in the query
# to values. This can be used to avoid XPath injection attacks
# or to automatically handle escaping string values.
#
# XPath.first( node )
# XPath.first( doc, "//b"} )
# XPath.first( node, "a/x:b", { "x"=>"http://doofus" } )
# XPath.first( node, '/book/publisher/text()=$publisher', {}, {"publisher"=>"O'Reilly"})
def XPath::first(element, path=nil, namespaces=nil, variables={}, options={})
raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash)
raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
parser = XPathParser.new(**options)
parser.namespaces = namespaces
parser.variables = variables
path = "*" unless path
element = [element] unless element.kind_of? Array
parser.parse(path, element).flatten[0]
end
# Iterates over nodes that match the given path, calling the supplied
# block with the match.
# element::
# The context element
# path::
# The xpath to search for. If not supplied or nil, defaults to '*'
# namespaces::
# If supplied, a Hash which defines a namespace mapping
# variables::
# If supplied, a Hash which maps $variables in the query
# to values. This can be used to avoid XPath injection attacks
# or to automatically handle escaping string values.
#
# XPath.each( node ) { |el| ... }
# XPath.each( node, '/*[@attr='v']' ) { |el| ... }
# XPath.each( node, 'ancestor::x' ) { |el| ... }
# XPath.each( node, '/book/publisher/text()=$publisher', {}, {"publisher"=>"O'Reilly"}) \
# {|el| ... }
def XPath::each(element, path=nil, namespaces=nil, variables={}, options={}, &block)
raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash)
raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
parser = XPathParser.new(**options)
parser.namespaces = namespaces
parser.variables = variables
path = "*" unless path
element = [element] unless element.kind_of? Array
parser.parse(path, element).each( &block )
end
# Returns an array of nodes matching a given XPath.
def XPath::match(element, path=nil, namespaces=nil, variables={}, options={})
parser = XPathParser.new(**options)
parser.namespaces = namespaces
parser.variables = variables
path = "*" unless path
element = [element] unless element.kind_of? Array
parser.parse(path,element)
end
end
end

Просмотреть файл

@ -1,968 +0,0 @@
# frozen_string_literal: false
require "pp"
require_relative 'namespace'
require_relative 'xmltokens'
require_relative 'attribute'
require_relative 'parsers/xpathparser'
class Object
# provides a unified +clone+ operation, for REXML::XPathParser
# to use across multiple Object types
def dclone
clone
end
end
class Symbol
# provides a unified +clone+ operation, for REXML::XPathParser
# to use across multiple Object types
def dclone ; self ; end
end
class Integer
# provides a unified +clone+ operation, for REXML::XPathParser
# to use across multiple Object types
def dclone ; self ; end
end
class Float
# provides a unified +clone+ operation, for REXML::XPathParser
# to use across multiple Object types
def dclone ; self ; end
end
class Array
# provides a unified +clone+ operation, for REXML::XPathParser
# to use across multiple Object+ types
def dclone
klone = self.clone
klone.clear
self.each{|v| klone << v.dclone}
klone
end
end
module REXML
# You don't want to use this class. Really. Use XPath, which is a wrapper
# for this class. Believe me. You don't want to poke around in here.
# There is strange, dark magic at work in this code. Beware. Go back! Go
# back while you still can!
class XPathParser
include XMLTokens
LITERAL = /^'([^']*)'|^"([^"]*)"/u
DEBUG = (ENV["REXML_XPATH_PARSER_DEBUG"] == "true")
def initialize(strict: false)
@debug = DEBUG
@parser = REXML::Parsers::XPathParser.new
@namespaces = nil
@variables = {}
@nest = 0
@strict = strict
end
def namespaces=( namespaces={} )
Functions::namespace_context = namespaces
@namespaces = namespaces
end
def variables=( vars={} )
Functions::variables = vars
@variables = vars
end
def parse path, nodeset
path_stack = @parser.parse( path )
match( path_stack, nodeset )
end
def get_first path, nodeset
path_stack = @parser.parse( path )
first( path_stack, nodeset )
end
def predicate path, nodeset
path_stack = @parser.parse( path )
match( path_stack, nodeset )
end
def []=( variable_name, value )
@variables[ variable_name ] = value
end
# Performs a depth-first (document order) XPath search, and returns the
# first match. This is the fastest, lightest way to return a single result.
#
# FIXME: This method is incomplete!
def first( path_stack, node )
return nil if path.size == 0
case path[0]
when :document
# do nothing
return first( path[1..-1], node )
when :child
for c in node.children
r = first( path[1..-1], c )
return r if r
end
when :qname
name = path[2]
if node.name == name
return node if path.size == 3
return first( path[3..-1], node )
else
return nil
end
when :descendant_or_self
r = first( path[1..-1], node )
return r if r
for c in node.children
r = first( path, c )
return r if r
end
when :node
return first( path[1..-1], node )
when :any
return first( path[1..-1], node )
end
return nil
end
def match(path_stack, nodeset)
nodeset = nodeset.collect.with_index do |node, i|
position = i + 1
XPathNode.new(node, position: position)
end
result = expr(path_stack, nodeset)
case result
when Array # nodeset
unnode(result)
else
[result]
end
end
private
def strict?
@strict
end
# Returns a String namespace for a node, given a prefix
# The rules are:
#
# 1. Use the supplied namespace mapping first.
# 2. If no mapping was supplied, use the context node to look up the namespace
def get_namespace( node, prefix )
if @namespaces
return @namespaces[prefix] || ''
else
return node.namespace( prefix ) if node.node_type == :element
return ''
end
end
# Expr takes a stack of path elements and a set of nodes (either a Parent
# or an Array and returns an Array of matching nodes
def expr( path_stack, nodeset, context=nil )
enter(:expr, path_stack, nodeset) if @debug
return nodeset if path_stack.length == 0 || nodeset.length == 0
while path_stack.length > 0
trace(:while, path_stack, nodeset) if @debug
if nodeset.length == 0
path_stack.clear
return []
end
op = path_stack.shift
case op
when :document
first_raw_node = nodeset.first.raw_node
nodeset = [XPathNode.new(first_raw_node.root_node, position: 1)]
when :self
nodeset = step(path_stack) do
[nodeset]
end
when :child
nodeset = step(path_stack) do
child(nodeset)
end
when :literal
trace(:literal, path_stack, nodeset) if @debug
return path_stack.shift
when :attribute
nodeset = step(path_stack, any_type: :attribute) do
nodesets = []
nodeset.each do |node|
raw_node = node.raw_node
next unless raw_node.node_type == :element
attributes = raw_node.attributes
next if attributes.empty?
nodesets << attributes.each_attribute.collect.with_index do |attribute, i|
XPathNode.new(attribute, position: i + 1)
end
end
nodesets
end
when :namespace
pre_defined_namespaces = {
"xml" => "http://www.w3.org/XML/1998/namespace",
}
nodeset = step(path_stack, any_type: :namespace) do
nodesets = []
nodeset.each do |node|
raw_node = node.raw_node
case raw_node.node_type
when :element
if @namespaces
nodesets << pre_defined_namespaces.merge(@namespaces)
else
nodesets << pre_defined_namespaces.merge(raw_node.namespaces)
end
when :attribute
if @namespaces
nodesets << pre_defined_namespaces.merge(@namespaces)
else
nodesets << pre_defined_namespaces.merge(raw_node.element.namespaces)
end
end
end
nodesets
end
when :parent
nodeset = step(path_stack) do
nodesets = []
nodeset.each do |node|
raw_node = node.raw_node
if raw_node.node_type == :attribute
parent = raw_node.element
else
parent = raw_node.parent
end
nodesets << [XPathNode.new(parent, position: 1)] if parent
end
nodesets
end
when :ancestor
nodeset = step(path_stack) do
nodesets = []
# new_nodes = {}
nodeset.each do |node|
raw_node = node.raw_node
new_nodeset = []
while raw_node.parent
raw_node = raw_node.parent
# next if new_nodes.key?(node)
new_nodeset << XPathNode.new(raw_node,
position: new_nodeset.size + 1)
# new_nodes[node] = true
end
nodesets << new_nodeset unless new_nodeset.empty?
end
nodesets
end
when :ancestor_or_self
nodeset = step(path_stack) do
nodesets = []
# new_nodes = {}
nodeset.each do |node|
raw_node = node.raw_node
next unless raw_node.node_type == :element
new_nodeset = [XPathNode.new(raw_node, position: 1)]
# new_nodes[node] = true
while raw_node.parent
raw_node = raw_node.parent
# next if new_nodes.key?(node)
new_nodeset << XPathNode.new(raw_node,
position: new_nodeset.size + 1)
# new_nodes[node] = true
end
nodesets << new_nodeset unless new_nodeset.empty?
end
nodesets
end
when :descendant_or_self
nodeset = step(path_stack) do
descendant(nodeset, true)
end
when :descendant
nodeset = step(path_stack) do
descendant(nodeset, false)
end
when :following_sibling
nodeset = step(path_stack) do
nodesets = []
nodeset.each do |node|
raw_node = node.raw_node
next unless raw_node.respond_to?(:parent)
next if raw_node.parent.nil?
all_siblings = raw_node.parent.children
current_index = all_siblings.index(raw_node)
following_siblings = all_siblings[(current_index + 1)..-1]
next if following_siblings.empty?
nodesets << following_siblings.collect.with_index do |sibling, i|
XPathNode.new(sibling, position: i + 1)
end
end
nodesets
end
when :preceding_sibling
nodeset = step(path_stack, order: :reverse) do
nodesets = []
nodeset.each do |node|
raw_node = node.raw_node
next unless raw_node.respond_to?(:parent)
next if raw_node.parent.nil?
all_siblings = raw_node.parent.children
current_index = all_siblings.index(raw_node)
preceding_siblings = all_siblings[0, current_index].reverse
next if preceding_siblings.empty?
nodesets << preceding_siblings.collect.with_index do |sibling, i|
XPathNode.new(sibling, position: i + 1)
end
end
nodesets
end
when :preceding
nodeset = step(path_stack, order: :reverse) do
unnode(nodeset) do |node|
preceding(node)
end
end
when :following
nodeset = step(path_stack) do
unnode(nodeset) do |node|
following(node)
end
end
when :variable
var_name = path_stack.shift
return [@variables[var_name]]
when :eq, :neq, :lt, :lteq, :gt, :gteq
left = expr( path_stack.shift, nodeset.dup, context )
right = expr( path_stack.shift, nodeset.dup, context )
res = equality_relational_compare( left, op, right )
trace(op, left, right, res) if @debug
return res
when :or
left = expr(path_stack.shift, nodeset.dup, context)
return true if Functions.boolean(left)
right = expr(path_stack.shift, nodeset.dup, context)
return Functions.boolean(right)
when :and
left = expr(path_stack.shift, nodeset.dup, context)
return false unless Functions.boolean(left)
right = expr(path_stack.shift, nodeset.dup, context)
return Functions.boolean(right)
when :div, :mod, :mult, :plus, :minus
left = expr(path_stack.shift, nodeset, context)
right = expr(path_stack.shift, nodeset, context)
left = unnode(left) if left.is_a?(Array)
right = unnode(right) if right.is_a?(Array)
left = Functions::number(left)
right = Functions::number(right)
case op
when :div
return left / right
when :mod
return left % right
when :mult
return left * right
when :plus
return left + right
when :minus
return left - right
else
raise "[BUG] Unexpected operator: <#{op.inspect}>"
end
when :union
left = expr( path_stack.shift, nodeset, context )
right = expr( path_stack.shift, nodeset, context )
left = unnode(left) if left.is_a?(Array)
right = unnode(right) if right.is_a?(Array)
return (left | right)
when :neg
res = expr( path_stack, nodeset, context )
res = unnode(res) if res.is_a?(Array)
return -Functions.number(res)
when :not
when :function
func_name = path_stack.shift.tr('-','_')
arguments = path_stack.shift
if nodeset.size != 1
message = "[BUG] Node set size must be 1 for function call: "
message += "<#{func_name}>: <#{nodeset.inspect}>: "
message += "<#{arguments.inspect}>"
raise message
end
node = nodeset.first
if context
target_context = context
else
target_context = {:size => nodeset.size}
if node.is_a?(XPathNode)
target_context[:node] = node.raw_node
target_context[:index] = node.position
else
target_context[:node] = node
target_context[:index] = 1
end
end
args = arguments.dclone.collect do |arg|
result = expr(arg, nodeset, target_context)
result = unnode(result) if result.is_a?(Array)
result
end
Functions.context = target_context
return Functions.send(func_name, *args)
else
raise "[BUG] Unexpected path: <#{op.inspect}>: <#{path_stack.inspect}>"
end
end # while
return nodeset
ensure
leave(:expr, path_stack, nodeset) if @debug
end
def step(path_stack, any_type: :element, order: :forward)
nodesets = yield
begin
enter(:step, path_stack, nodesets) if @debug
nodesets = node_test(path_stack, nodesets, any_type: any_type)
while path_stack[0] == :predicate
path_stack.shift # :predicate
predicate_expression = path_stack.shift.dclone
nodesets = evaluate_predicate(predicate_expression, nodesets)
end
if nodesets.size == 1
ordered_nodeset = nodesets[0]
else
raw_nodes = []
nodesets.each do |nodeset|
nodeset.each do |node|
if node.respond_to?(:raw_node)
raw_nodes << node.raw_node
else
raw_nodes << node
end
end
end
ordered_nodeset = sort(raw_nodes, order)
end
new_nodeset = []
ordered_nodeset.each do |node|
# TODO: Remove duplicated
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
end
new_nodeset
ensure
leave(:step, path_stack, new_nodeset) if @debug
end
end
def node_test(path_stack, nodesets, any_type: :element)
enter(:node_test, path_stack, nodesets) if @debug
operator = path_stack.shift
case operator
when :qname
prefix = path_stack.shift
name = path_stack.shift
new_nodesets = nodesets.collect do |nodeset|
filter_nodeset(nodeset) do |node|
raw_node = node.raw_node
case raw_node.node_type
when :element
if prefix.nil?
raw_node.name == name
elsif prefix.empty?
if strict?
raw_node.name == name and raw_node.namespace == ""
else
# FIXME: This DOUBLES the time XPath searches take
ns = get_namespace(raw_node, prefix)
raw_node.name == name and raw_node.namespace == ns
end
else
# FIXME: This DOUBLES the time XPath searches take
ns = get_namespace(raw_node, prefix)
raw_node.name == name and raw_node.namespace == ns
end
when :attribute
if prefix.nil?
raw_node.name == name
elsif prefix.empty?
raw_node.name == name and raw_node.namespace == ""
else
# FIXME: This DOUBLES the time XPath searches take
ns = get_namespace(raw_node.element, prefix)
raw_node.name == name and raw_node.namespace == ns
end
else
false
end
end
end
when :namespace
prefix = path_stack.shift
new_nodesets = nodesets.collect do |nodeset|
filter_nodeset(nodeset) do |node|
raw_node = node.raw_node
case raw_node.node_type
when :element
namespaces = @namespaces || raw_node.namespaces
raw_node.namespace == namespaces[prefix]
when :attribute
namespaces = @namespaces || raw_node.element.namespaces
raw_node.namespace == namespaces[prefix]
else
false
end
end
end
when :any
new_nodesets = nodesets.collect do |nodeset|
filter_nodeset(nodeset) do |node|
raw_node = node.raw_node
raw_node.node_type == any_type
end
end
when :comment
new_nodesets = nodesets.collect do |nodeset|
filter_nodeset(nodeset) do |node|
raw_node = node.raw_node
raw_node.node_type == :comment
end
end
when :text
new_nodesets = nodesets.collect do |nodeset|
filter_nodeset(nodeset) do |node|
raw_node = node.raw_node
raw_node.node_type == :text
end
end
when :processing_instruction
target = path_stack.shift
new_nodesets = nodesets.collect do |nodeset|
filter_nodeset(nodeset) do |node|
raw_node = node.raw_node
(raw_node.node_type == :processing_instruction) and
(target.empty? or (raw_node.target == target))
end
end
when :node
new_nodesets = nodesets.collect do |nodeset|
filter_nodeset(nodeset) do |node|
true
end
end
else
message = "[BUG] Unexpected node test: " +
"<#{operator.inspect}>: <#{path_stack.inspect}>"
raise message
end
new_nodesets
ensure
leave(:node_test, path_stack, new_nodesets) if @debug
end
def filter_nodeset(nodeset)
new_nodeset = []
nodeset.each do |node|
next unless yield(node)
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
end
new_nodeset
end
def evaluate_predicate(expression, nodesets)
enter(:predicate, expression, nodesets) if @debug
new_nodesets = nodesets.collect do |nodeset|
new_nodeset = []
subcontext = { :size => nodeset.size }
nodeset.each_with_index do |node, index|
if node.is_a?(XPathNode)
subcontext[:node] = node.raw_node
subcontext[:index] = node.position
else
subcontext[:node] = node
subcontext[:index] = index + 1
end
result = expr(expression.dclone, [node], subcontext)
trace(:predicate_evaluate, expression, node, subcontext, result) if @debug
result = result[0] if result.kind_of? Array and result.length == 1
if result.kind_of? Numeric
if result == node.position
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
end
elsif result.instance_of? Array
if result.size > 0 and result.inject(false) {|k,s| s or k}
if result.size > 0
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
end
end
else
if result
new_nodeset << XPathNode.new(node, position: new_nodeset.size + 1)
end
end
end
new_nodeset
end
new_nodesets
ensure
leave(:predicate, new_nodesets) if @debug
end
def trace(*args)
indent = " " * @nest
PP.pp(args, "").each_line do |line|
puts("#{indent}#{line}")
end
end
def enter(tag, *args)
trace(:enter, tag, *args)
@nest += 1
end
def leave(tag, *args)
@nest -= 1
trace(:leave, tag, *args)
end
# Reorders an array of nodes so that they are in document order
# It tries to do this efficiently.
#
# FIXME: I need to get rid of this, but the issue is that most of the XPath
# interpreter functions as a filter, which means that we lose context going
# in and out of function calls. If I knew what the index of the nodes was,
# I wouldn't have to do this. Maybe add a document IDX for each node?
# Problems with mutable documents. Or, rewrite everything.
def sort(array_of_nodes, order)
new_arry = []
array_of_nodes.each { |node|
node_idx = []
np = node.node_type == :attribute ? node.element : node
while np.parent and np.parent.node_type == :element
node_idx << np.parent.index( np )
np = np.parent
end
new_arry << [ node_idx.reverse, node ]
}
ordered = new_arry.sort_by do |index, node|
if order == :forward
index
else
-index
end
end
ordered.collect do |_index, node|
node
end
end
def descendant(nodeset, include_self)
nodesets = []
nodeset.each do |node|
new_nodeset = []
new_nodes = {}
descendant_recursive(node.raw_node, new_nodeset, new_nodes, include_self)
nodesets << new_nodeset unless new_nodeset.empty?
end
nodesets
end
def descendant_recursive(raw_node, new_nodeset, new_nodes, include_self)
if include_self
return if new_nodes.key?(raw_node)
new_nodeset << XPathNode.new(raw_node, position: new_nodeset.size + 1)
new_nodes[raw_node] = true
end
node_type = raw_node.node_type
if node_type == :element or node_type == :document
raw_node.children.each do |child|
descendant_recursive(child, new_nodeset, new_nodes, true)
end
end
end
# Builds a nodeset of all of the preceding nodes of the supplied node,
# in reverse document order
# preceding:: includes every element in the document that precedes this node,
# except for ancestors
def preceding(node)
ancestors = []
parent = node.parent
while parent
ancestors << parent
parent = parent.parent
end
precedings = []
preceding_node = preceding_node_of(node)
while preceding_node
if ancestors.include?(preceding_node)
ancestors.delete(preceding_node)
else
precedings << XPathNode.new(preceding_node,
position: precedings.size + 1)
end
preceding_node = preceding_node_of(preceding_node)
end
precedings
end
def preceding_node_of( node )
psn = node.previous_sibling_node
if psn.nil?
if node.parent.nil? or node.parent.class == Document
return nil
end
return node.parent
#psn = preceding_node_of( node.parent )
end
while psn and psn.kind_of? Element and psn.children.size > 0
psn = psn.children[-1]
end
psn
end
def following(node)
followings = []
following_node = next_sibling_node(node)
while following_node
followings << XPathNode.new(following_node,
position: followings.size + 1)
following_node = following_node_of(following_node)
end
followings
end
def following_node_of( node )
if node.kind_of? Element and node.children.size > 0
return node.children[0]
end
return next_sibling_node(node)
end
def next_sibling_node(node)
psn = node.next_sibling_node
while psn.nil?
if node.parent.nil? or node.parent.class == Document
return nil
end
node = node.parent
psn = node.next_sibling_node
end
return psn
end
def child(nodeset)
nodesets = []
nodeset.each do |node|
raw_node = node.raw_node
node_type = raw_node.node_type
# trace(:child, node_type, node)
case node_type
when :element
nodesets << raw_node.children.collect.with_index do |child_node, i|
XPathNode.new(child_node, position: i + 1)
end
when :document
new_nodeset = []
raw_node.children.each do |child|
case child
when XMLDecl, Text
# Ignore
else
new_nodeset << XPathNode.new(child, position: new_nodeset.size + 1)
end
end
nodesets << new_nodeset unless new_nodeset.empty?
end
end
nodesets
end
def norm b
case b
when true, false
return b
when 'true', 'false'
return Functions::boolean( b )
when /^\d+(\.\d+)?$/, Numeric
return Functions::number( b )
else
return Functions::string( b )
end
end
def equality_relational_compare(set1, op, set2)
set1 = unnode(set1) if set1.is_a?(Array)
set2 = unnode(set2) if set2.is_a?(Array)
if set1.kind_of? Array and set2.kind_of? Array
# If both objects to be compared are node-sets, then the
# comparison will be true if and only if there is a node in the
# first node-set and a node in the second node-set such that the
# result of performing the comparison on the string-values of
# the two nodes is true.
set1.product(set2).any? do |node1, node2|
node_string1 = Functions.string(node1)
node_string2 = Functions.string(node2)
compare(node_string1, op, node_string2)
end
elsif set1.kind_of? Array or set2.kind_of? Array
# If one is nodeset and other is number, compare number to each item
# in nodeset s.t. number op number(string(item))
# If one is nodeset and other is string, compare string to each item
# in nodeset s.t. string op string(item)
# If one is nodeset and other is boolean, compare boolean to each item
# in nodeset s.t. boolean op boolean(item)
if set1.kind_of? Array
a = set1
b = set2
else
a = set2
b = set1
end
case b
when true, false
each_unnode(a).any? do |unnoded|
compare(Functions.boolean(unnoded), op, b)
end
when Numeric
each_unnode(a).any? do |unnoded|
compare(Functions.number(unnoded), op, b)
end
when /\A\d+(\.\d+)?\z/
b = Functions.number(b)
each_unnode(a).any? do |unnoded|
compare(Functions.number(unnoded), op, b)
end
else
b = Functions::string(b)
each_unnode(a).any? do |unnoded|
compare(Functions::string(unnoded), op, b)
end
end
else
# If neither is nodeset,
# If op is = or !=
# If either boolean, convert to boolean
# If either number, convert to number
# Else, convert to string
# Else
# Convert both to numbers and compare
compare(set1, op, set2)
end
end
def value_type(value)
case value
when true, false
:boolean
when Numeric
:number
when String
:string
else
raise "[BUG] Unexpected value type: <#{value.inspect}>"
end
end
def normalize_compare_values(a, operator, b)
a_type = value_type(a)
b_type = value_type(b)
case operator
when :eq, :neq
if a_type == :boolean or b_type == :boolean
a = Functions.boolean(a) unless a_type == :boolean
b = Functions.boolean(b) unless b_type == :boolean
elsif a_type == :number or b_type == :number
a = Functions.number(a) unless a_type == :number
b = Functions.number(b) unless b_type == :number
else
a = Functions.string(a) unless a_type == :string
b = Functions.string(b) unless b_type == :string
end
when :lt, :lteq, :gt, :gteq
a = Functions.number(a) unless a_type == :number
b = Functions.number(b) unless b_type == :number
else
message = "[BUG] Unexpected compare operator: " +
"<#{operator.inspect}>: <#{a.inspect}>: <#{b.inspect}>"
raise message
end
[a, b]
end
def compare(a, operator, b)
a, b = normalize_compare_values(a, operator, b)
case operator
when :eq
a == b
when :neq
a != b
when :lt
a < b
when :lteq
a <= b
when :gt
a > b
when :gteq
a >= b
else
message = "[BUG] Unexpected compare operator: " +
"<#{operator.inspect}>: <#{a.inspect}>: <#{b.inspect}>"
raise message
end
end
def each_unnode(nodeset)
return to_enum(__method__, nodeset) unless block_given?
nodeset.each do |node|
if node.is_a?(XPathNode)
unnoded = node.raw_node
else
unnoded = node
end
yield(unnoded)
end
end
def unnode(nodeset)
each_unnode(nodeset).collect do |unnoded|
unnoded = yield(unnoded) if block_given?
unnoded
end
end
end
# @private
class XPathNode
attr_reader :raw_node, :context
def initialize(node, context=nil)
if node.is_a?(XPathNode)
@raw_node = node.raw_node
else
@raw_node = node
end
@context = context || {}
end
def position
@context[:position]
end
end
end

Двоичные данные
test/rexml/data/LostineRiver.kml.gz

Двоичный файл не отображается.

Просмотреть файл

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ProductionSupport version="1.1" >
<Errors>
<CommonErrors>
<CommonError>
<Key><![CDATA[RoyUpdatePolicyBusReq(Object)>>#error:]]></Key>
<Patterns>
<Pattern><![CDATA[The error code is '9997']]></Pattern>
</Patterns>
<Message>
<String>Update Policy request 9997: Please check CICS log</String>
</Message>
<BackendSupport/>
</CommonError>
<CommonError>
<Key>MotorInsuranceContract(Object)>>#error:</Key>
<Patterns>
<Pattern>Have not got a complete</Pattern>
</Patterns>
<Message>
<String>Have not got a complete and consistent set of price matrices for policy period - ask back-end prod supp to sort out</String>
</Message>
<BackendSupport/>
</CommonError>
</CommonErrors>
</Errors>
</ProductionSupport>

Просмотреть файл

@ -1,25 +0,0 @@
<?xml version="1.0"?>
<root>
<a>
<a.1/>
<a.2/>
<a.3/>
<a.4/>
<a.5/>
</a>
<b>
<b.1/>
<b.2/>
<b.3/>
<b.4/>
<b.5/>
<b.6/>
<b.7/>
<b.8/>
<b.9/>
</b>
</root>

Просмотреть файл

@ -1,5 +0,0 @@
<a>
Here is an XML document.
<b>
It has some elements, but it also has a hidden < error! (or two)
</a>

Просмотреть файл

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<foo>
<bar>
<baz/>
<cheese/>
<baz/>
<cheese/>
<baz/>
</bar>
</foo>

Просмотреть файл

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xu:modifications xmlns:xu="http://www.xmldb.org/xupdate">
<xu:append select="/foo/bar/cheese[1]">
Goudse kaas
<edam type="jong belegen">Rond</edam>
</xu:append>
<xu:remove select="/foo/bar/baz[2]"/>
<xu:if test="/foo">
<xu:insert-before select="/foo/bar/baz[2]">
<cheese>More cheese!</cheese>
</xu:insert-before>
</xu:if>
<xu:insert-before select="/foo/bar/baz[2]">
<cheese>Even more cheese!</cheese>
</xu:insert-before>
<xu:if test="/bar">
<xu:insert-before select="/foo/bar/baz[2]">
<sausages>No sausages today</sausages>
</xu:insert-before>
</xu:if>
<xu:variable
xmlns:private="http://www.jaxen.org/private"
name="private:twice">
<cracker/>
<!-- champagne -->
<?oisters with a bit of lemon?>
</xu:variable>
<xu:variable name="twice" select="'Twice'"/>
<xu:insert-after
select="/foo/bar"
xmlns:private="http://www.jaxen.org/private"
>
<xu:value-of select="$private:twice"/>
<xu:value-of select="$private:twice"/>
<xu:value-of select="$twice"/>
</xu:insert-after>
</xu:modifications>

Просмотреть файл

@ -1,20 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE rdf:RDF [
<!ENTITY % HTMLlat1 PUBLIC
"-//W3C//ENTITIES Latin 1 for XHTML//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
%HTMLlat1;
]>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:on="http://www.oreillynet.com/csrss/"
xmlns="http://purl.org/rss/1.0/"
>
<channel rdf:about="http://www.oreillynet.com/">
<title>O'Reilly Network Articles</title>
<link>http://www.oreillynet.com/</link>
</channel>
</rdf:RDF>

Просмотреть файл

@ -1,70 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="XSL\JavaXML.html.xsl" type="text/xsl"?>
<?xml-stylesheet href="XSL\JavaXML.wml.xsl" type="text/xsl"
media="wap"?>
<?cocoon-process type="xslt"?>
<!-- Java and XML -->
<JavaXML:Book xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/"
xmlns:ora="http://www.oreilly.com"
xmlns:unused="http://www.unused.com"
ora:category="Java"
>
<!-- comment one -->
<!-- comment two -->
<JavaXML:Title>Java and XML</JavaXML:Title>
<JavaXML:Contents xmlns:topic="http://www.oreilly.com/topics">
<JavaXML:Chapter topic:focus="XML">
<JavaXML:Heading>Introduction</JavaXML:Heading>
<JavaXML:Topic subSections="7">
What Is It?
</JavaXML:Topic>
<JavaXML:Topic subSections="3">
How Do I Use It?
</JavaXML:Topic>
<JavaXML:Topic subSections="4">
Why Should I Use It?
</JavaXML:Topic>
<JavaXML:Topic subSections="0">
What's Next?
</JavaXML:Topic>
</JavaXML:Chapter>
<JavaXML:Chapter topic:focus="XML">
<JavaXML:Heading>Creating XML</JavaXML:Heading>
<JavaXML:Topic subSections="0">An XML Document</JavaXML:Topic>
<JavaXML:Topic subSections="2">The Header</JavaXML:Topic>
<JavaXML:Topic subSections="6">The Content</JavaXML:Topic>
<JavaXML:Topic subSections="1">What's Next?</JavaXML:Topic>
</JavaXML:Chapter>
<JavaXML:Chapter topic:focus="Java">
<JavaXML:Heading>Parsing XML</JavaXML:Heading>
<JavaXML:Topic subSections="3">Getting Prepared</JavaXML:Topic>
<JavaXML:Topic subSections="3">SAX Readers</JavaXML:Topic>
<JavaXML:Topic subSections="9">Content Handlers</JavaXML:Topic>
<JavaXML:Topic subSections="4">Error Handlers</JavaXML:Topic>
<JavaXML:Topic subSections="0">
A Better Way to Load a Parser
</JavaXML:Topic>
<JavaXML:Topic subSections="4">"Gotcha!"</JavaXML:Topic>
<JavaXML:Topic subSections="0">What's Next?</JavaXML:Topic>
</JavaXML:Chapter>
<JavaXML:SectionBreak/>
<JavaXML:Chapter topic:focus="Java">
<JavaXML:Heading>Web Publishing Frameworks</JavaXML:Heading>
<JavaXML:Topic subSections="4">Selecting a Framework</JavaXML:Topic>
<JavaXML:Topic subSections="4">Installation</JavaXML:Topic>
<JavaXML:Topic subSections="3">
Using a Publishing Framework
</JavaXML:Topic>
<JavaXML:Topic subSections="2">XSP</JavaXML:Topic>
<JavaXML:Topic subSections="3">Cocoon 2.0 and Beyond</JavaXML:Topic>
<JavaXML:Topic subSections="0">What's Next?</JavaXML:Topic>
</JavaXML:Chapter>
</JavaXML:Contents>
</JavaXML:Book>

Просмотреть файл

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<content-repository>
<content-repository-child-1>
<content-1>content-1-text</content-1>
</content-repository-child-1>
<content-repository-child-2>
<content-2>content-2-text</content-2>
</content-repository-child-2>
<content-repository-child-3>
<content-3>content-3-text</content-3>
</content-repository-child-3>
</content-repository>

Просмотреть файл

@ -1,6 +0,0 @@
<?xml version="1.0"?>
<a xmlns="http://dummyNamespace/">
<b>
<c>Hello</c>
</b>
</a>

Просмотреть файл

@ -1,34 +0,0 @@
<!DOCTYPE internationalization SYSTEM "l10n.dtd" [
<!ENTITY af SYSTEM "af.xml">
<!ENTITY ca SYSTEM "ca.xml">
<!ENTITY cs SYSTEM "cs.xml">
<!ENTITY da SYSTEM "da.xml">
<!ENTITY de SYSTEM "de.xml">
<!ENTITY el SYSTEM "el.xml">
<!ENTITY en SYSTEM "en.xml">
<!ENTITY es SYSTEM "es.xml">
<!ENTITY et SYSTEM "et.xml">
<!ENTITY fi SYSTEM "fi.xml">
<!ENTITY fr SYSTEM "fr.xml">
<!ENTITY hu SYSTEM "hu.xml">
<!ENTITY id SYSTEM "id.xml">
<!ENTITY it SYSTEM "it.xml">
<!ENTITY ja SYSTEM "ja.xml">
<!ENTITY ko SYSTEM "ko.xml">
<!ENTITY nl SYSTEM "nl.xml">
<!ENTITY no SYSTEM "no.xml">
<!ENTITY no_ny SYSTEM "no_ny.xml">
<!ENTITY pl SYSTEM "pl.xml">
<!ENTITY pt SYSTEM "pt.xml">
<!ENTITY pt_br SYSTEM "pt_br.xml">
<!ENTITY ro SYSTEM "ro.xml">
<!ENTITY ru SYSTEM "ru.xml">
<!ENTITY sk SYSTEM "sk.xml">
<!ENTITY sl SYSTEM "sl.xml">
<!ENTITY sr SYSTEM "sr.xml">
<!ENTITY sv SYSTEM "sv.xml">
<!ENTITY tr SYSTEM "tr.xml">
<!ENTITY zh_cn SYSTEM "zh_cn.xml">
<!ENTITY zh_tw SYSTEM "zh_tw.xml">
]>
<x/>

Просмотреть файл

@ -1,542 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="http://www.germane-software.com/repositories/public/documentation/documentation.css"?>
<?xml-stylesheet alternative="yes" type="text/css" href="file:/home/ser/Work/documentation/documentation.css"?>
<?xml-stylesheet alternative="yes" type="text/xsl" href="http://www.germane-software.com/repositories/public/documentation/paged.xsl"?>
<!DOCTYPE documentation SYSTEM "http://www.germane-software.com/repositories/public/documentation/documentation.dtd">
<documentation>
<head>
<title>REXML</title>
<banner href="img/rexml.png" />
<version>@ANT_VERSION@</version>
<date>@ANT_DATE@</date>
<home>http://www.germane-software.com/software/rexml</home>
<base>rexml</base>
<language>ruby</language>
<author email="ser@germane-software.com"
href="http://www.ser1.net/" jabber="seanerussell@gmail.com">Sean
Russell</author>
</head>
<overview>
<purpose lang="en">
<p>REXML is a conformant XML processor for the Ruby programming
language. REXML passes 100% of the Oasis non-validating tests and
includes full XPath support. It is reasonably fast, and is implemented
in pure Ruby. Best of all, it has a clean, intuitive API. REXML is
included in the standard library of Ruby</p>
<p>This software is distribute under the <link href="LICENSE.txt">Ruby
license</link>.</p>
</purpose>
<general>
<p>REXML arose out of a desire for a straightforward XML API, and is an
attempt at an API that doesn't require constant referencing of
documentation to do common tasks. "Keep the common case simple, and the
uncommon, possible."</p>
<p>REXML avoids The DOM API, which violates the maxim of simplicity. It
does provide <em>a</em> DOM model, but one that is Ruby-ized. It is an
XML API oriented for Ruby programmers, not for XML programmers coming
from Java.</p>
<p>Some of the common differences are that the Ruby API relies on block
enumerations, rather than iterators. For example, the Java code:</p>
<example>for (Enumeration e=parent.getChildren(); e.hasMoreElements(); ) {
Element child = (Element)e.nextElement(); // Do something with child
}</example>
<p>in Ruby becomes:</p>
<example>parent.each_child{ |child| # Do something with child }</example>
<p>Can't you feel the peace and contentment in this block of code? Ruby
is the language Buddha would have programmed in.</p>
<p>One last thing. If you use and like this software, and you're in a
position of power in a company in Western Europe and are looking for a
software architect or developer, drop me a line. I took a lot of French
classes in college (all of which I've forgotten), and I lived in Munich
long enough that I was pretty fluent by the time I left, and I'd love to
get back over there.</p>
</general>
<features lang="en">
<item>Four intuitive parsing APIs.</item>
<item>Intuitive, powerful, and reasonably fast tree parsing API (a-la
DOM</item>
<item>Fast stream parsing API (a-la SAX)<footnote>This is not a SAX
API.</footnote></item>
<item>SAX2-based API<footnote>In addition to the native REXML streaming
API. This is slower than the native REXML API, but does a lot more work
for you.</footnote></item>
<item>Pull parsing API.</item>
<item>Small</item>
<item>Reasonably fast (for interpreted code)</item>
<item>Native Ruby</item>
<item>Full XPath support<footnote>Currently only available for the tree
API</footnote></item>
<item>XML 1.0 conformant<footnote>REXML passes all of the non-validating
OASIS tests. There are probably places where REXML isn't conformant, but
I try to fix them as they're reported.</footnote></item>
<item>ISO-8859-1, UNILE, UTF-16 and UTF-8 input and output; also,
support for any encoding the iconv supports.</item>
<item>Documentation</item>
</features>
</overview>
<operation lang="en">
<subsection title="Installation">
<p>You don't <em>have</em> to install anything; if you're running a
version of Ruby greater than 1.8, REXML is included. However, if you
choose to upgrade from the REXML distribution, run the command:
<code>ruby bin/install.rb</code>. By the way, you really should look at
these sorts of files before you run them as root. They could contain
anything, and since (in Ruby, at least) they tend to be mercifully
short, it doesn't hurt to glance over them. If you want to uninstall
REXML, run <code>ruby bin/install.rb -u</code>.</p>
</subsection>
<subsection title="Unit tests">
<p>If you have Test::Unit installed, you can run the unit test cases.
Run the command: <code>ruby bin/suite.rb</code>; it runs against the
distribution, not against the installed version.</p>
</subsection>
<subsection title="Benchmarks">
<p>There is a benchmark suite in <code>benchmarks/</code>. To run the
benchmarks, change into that directory and run <code>ruby
comparison.rb</code>. If you have nothing else installed, only the
benchmarks for REXML will be run. However, if you have any of the
following installed, benchmarks for those tools will also be run:</p>
<list>
<item>NQXML</item>
<item>XMLParser</item>
<item>Electric XML (you must copy <code>EXML.jar</code> into the
<code>benchmarks</code> directory and compile
<code>flatbench.java</code> before running the test)</item>
</list>
<p>The results will be written to <code>index.html</code>.</p>
</subsection>
<subsection title="General Usage">
<p>Please see <link href="docs/tutorial.html">the Tutorial</link>.</p>
<p>The API documentation is available <link
href="http://www.germane-software.com/software/XML/rexml/doc">on-line</link>,
or it can be downloaded as an archive <link
href="http://www.germane-software.com/software/archives/rexml_api_@ANT_VERSION@.tgz">in
tgz format (~70Kb)</link> or (if you're a masochist) <link
href="http://www.germane-software.com/software/archives/rexml_api_@ANT_VERSION@.zip">in
zip format (~280Kb)</link>. The best solution is to download and install
Dave Thomas' most excellent <link
href="http://rdoc.sourceforge.net">rdoc</link> and generate the API docs
yourself; then you'll be sure to have the latest API docs and won't have
to keep downloading the doc archive.</p>
<p>The unit tests in <code>test/</code> and the benchmarking code in
<code>benchmark/</code> provide additional examples of using REXML. The
Tutorial provides examples with commentary. The documentation unpacks
into <link href="doc/index.html"><code>rexml/doc</code></link>.</p>
<p>Kouhei Sutou maintains a <link
href="http://www.germane-software.com/software/rexml_doc_ja/current/index.html">Japanese
version</link> of the REXML API docs. <link
href="http://www.germane-software.com/software/rexml_doc_ja/current/japanese_documentation.html">Kou's
documentation page</link> contains links to binary archives for various
versions of the documentation.</p>
</subsection>
</operation>
<status>
<subsection title="Speed and Completeness">
<p>Unfortunately, NQXML is the only package REXML can be compared
against; XMLParser uses expat, which is a native library, and really is
a different beast altogether. So in comparing NQXML and REXML you can
look at four things: speed, size, completeness, and API.</p>
<p><link href="benchmarks/index.html">Benchmarks</link></p>
<p>REXML is faster than NQXML in some things, and slower than NQXML in a
couple of things. You can see this for yourself by running the supplied
benchmarks. Most of the places where REXML are slower are because of the
convenience methods<footnote>For example,
<code>element.elements[index]</code> isn't really an array operation;
index can be an Integer or an XPath, and this feature is relatively time
expensive.</footnote>. On the positive side, most of the convenience
methods can be bypassed if you know what you are doing. Check the <link
href="benchmarks/index.html"> benchmark comparison page</link> for a
<em>general</em> comparison. You can look at the benchmark code yourself
to decide how much salt to take with them.</p>
<p>The sizes of the XML parsers are close<footnote>As measured with
<code>ruby -nle 'print unless /^\s*(#.*|)$/' *.rb | wc -l</code>
</footnote>. NQXML 1.1.3 has 1580 non-blank, non-comment lines of code;
REXML 2.0 has 2340<footnote>REXML started out with about 1200, but that
number has been steadily increasing as features are added. XPath
accounts for 541 lines of that code, so the core REXML has about 1800
LOC.</footnote>.</p>
<p>REXML is a conformant XML 1.0 parser. It supports multiple language
encodings, and internal processing uses the required UTF-8 and UTF-16
encodings. It passes 100% of the Oasis non-validating tests.
Furthermore, it provides a full implementation of XPath, a SAX2 and a
PullParser API.</p>
</subsection>
<subsection title="XPath">
<p>As of release 2.0, XPath 1.0 is fully implemented.</p>
<p>I fully expect bugs to crop up from time to time, so if you see any
bogus XPath results, please let me know. That said, since I'm now
following the XPath grammar and spec fairly closely, I suspect that you
won't be surprised by REXML's XPath very often, and it should become
rock solid fairly quickly.</p>
<p>Check the "bugs" section for known problems; there are little bits of
XPath here and there that are not yet implemented, but I'll get to them
soon.</p>
<p>Namespace support is rather odd, but it isn't my fault. I can only do
so much and still conform to the specs. In particular, XPath attempts to
help as much as possible. Therefore, in the trivial cases, you can pass
namespace prefixes to Element.elements[...] and so on -- in these cases,
XPath will use the namespace environment of the base element you're
starting your XPath search from. However, if you want to do something
more complex, like pass in your own namespace environment, you have to
use the XPath first(), each(), and match() methods. Also, default
namespaces <em>force</em> you to use the XPath methods, rather than the
convenience methods, because there is no way for XPath to know what the
mappings for the default namespaces should be. This is exactly why I
loath namespaces -- a pox on the person(s) who thought them up!</p>
</subsection>
<subsection title="Namespaces">
<p>Namespace support is now fairly stable. One thing to be aware of is
that REXML is not (yet) a validating parser. This means that some
invalid namespace declarations are not caught.</p>
</subsection>
<subsection title="Mailing list">
<p>There is a low-volume mailing list dedicated to REXML. To subscribe,
send an empty email to <link
href="mailto:ser-rexml-subscribe@germane-software.com">ser-rexml-subscribe@germane-software.com</link>.
This list is more or less spam proof. To unsubscribe, similarly send a
message to <link
href="mailto:ser-rexml-unsubscribe@germane-software.com">ser-rexml-unsubscribe@germane-software.com</link>.</p>
</subsection>
<subsection title="RSS">
<p>An <link
href="http://www.germane-software.com/projects/rexml/timeline?ticket=on&amp;max=50&amp;daysback=90&amp;format=rss">RSS
file</link> for REXML is now being generated from the change log. This
allows you to be alerted of bug fixes and feature additions via "pull".
<link href="http://www.germane-software.com/software/rexml/rss.xml">Another
RSS</link> is available which contains a single item: the release notice
for the most recent release. This is an abuse of the RSS
mechanism, which was intended to be a distribution system for headlines
linked back to full articles, but it works. The headline for REXML is
the version number, and the description is the change log. The links all
link back to the REXML home page. The URL for the RSS itself is
http://www.germane-software.com/software/rexml/rss.xml.</p>
<p>The <link href="release.html">changelog itself is here</link>.</p>
<p>For those who are interested, there's a <link
href="docs/sloccount.txt">SLOCCount</link> (by David A. Wheeler) file
with stats on the REXML sourcecode. Note that the SLOCCount output
includes the files in the test/, benchmarks/, and bin/ directories, as
well as the main sourcecode for REXML itself.</p>
</subsection>
<subsection title="Applications that use REXML">
<list>
<item><link
href="http://www.pablotron.org/software/raggle/">Raggle</link> is a
console-based RSS aggregator.</item>
<item><link
href="http://www.zweknu.org/technical/index.rhtml?s=p|10/">getrss</link>
is an RSS aggregator</item>
<item>Ned Konz's <link
href="http://www.bikenomad.microship.com/ruby/">ruby-htmltools</link>
uses REXML</item>
<item>Hiroshi NAKAMURA's <link
href="http://www.ruby-lang.org/en/raa-list.rhtml?name=SOAP4R">SOAP4R</link>
package can use REXML as the XML processor.</item>
<item>Chris Morris' <link href="http://clabs.org/clxmlserial.htm">XML
Serializer</link>. XML Serializer provides a serialization mechanism
for Ruby that provides a bidirectional mapping between Ruby classes
and XML documents.</item>
<item>Much of the <link href="http://www.rubyxml.com">RubyXML</link>
site is generated with scripts that use REXML. RubyXML is a great
place to find information about th intersection between Ruby and
XML.</item>
</list>
</subsection>
<bugs lang="en">
<p>You can submit bug reports and feature requests, and view the list of
known bugs, at the <link
href="http://www.germane-software.com/projects/rexml">REXML bug report
page.</link> Please do submit bug reports. If you really want your bug
fixed fast, include an runit or Test::Unit method (or methods) that
illustrates the problem. At the very least, send me some XML that REXML
doesn't process properly.</p>
<p>You don't have to send an entire test suite -- just the unit test
methods. If you don't send me a unit test, I'll have to write one
myself, which will mean that your bug will take longer to fix.</p>
<p>When submitting bug reports, please include the version of Ruby and
of REXML that you're using, and the operating system you're running on.
Just run: <code>ruby -vrrexml/rexml -e 'p
REXML::VERSION,PLATFORM'</code> and paste the results in your bug
report. Include your email if you want a response about the bug.</p>
<item>Attributes are not handled internally as nodes, so you can't
perform node functions on them. This will have to change. It'll also
probably mean that, rather than returning attribute values, XPath will
return the Attribute nodes.</item>
<item>Some of the XPath <em>functions</em> are untested<footnote>Mike
Stok has been testing, debugging, and implementing some of these
Functions (and he's been doing a good job) so there's steady improvement
in this area.</footnote>. Any XPath functions that don't work are also
bugs... please report them. If you send a unit test that illustrates the
problem, I'll try to fix the problem within a couple of days (if I can)
and send you a patch, personally.</item>
<item>Accessing prefixes for which there is no defined namespace in an
XPath should throw an exception. It currently doesn't -- it just fails
to match.</item>
</bugs>
<todo lang="en">
<item>Reparsing a tree with a pull/SAX parser</item>
<item>Better namespace support in SAX</item>
<item>Lazy tree parsing</item>
<item>Segregate parsers, for optimized minimal distributions</item>
<item>XML &lt;-&gt; Ruby</item>
<item>Validation support</item>
<item>True XML character support</item>
<item>Add XPath support for streaming APIs</item>
<item status="request">XQuery support</item>
<item status="request">XUpdate support</item>
<item>Make sure namespaces are supported in pull parser</item>
<item status="request">Add document start and entity replacement events
in pull parser</item>
<item>Better stream parsing exception handling</item>
<item>I'd like to hack XMLRPC4R to use REXML, for my own
purposes.</item>
</todo>
</status>
<faq>
<q>REXML is hanging while parsing one of my XML files.</q>
<a>Your XML is probably malformed. Some malformed XML, especially XML that
contains literal '&lt;' embedded in the document, causes REXML to hang.
REXML should be throwing an exception, but it doesn't; this is a bug. I'm
aware that it is an extremely annoying bug, and it is one I'm trying to
solve in a way that doesn't significantly reduce REXML's parsing
speed.</a>
<q>I'm using the XPath '//foo' on an XML branch node X, and keep getting
all of the 'foo' elements in the entire document. Why? Shouldn't it return
only the 'foo' element descendants of X?</q>
<a>No. XPath specifies that '/' returns the document root, regardless of
the context node. '//' also starts at the document root. If you want to
limit your search to a branch, you need to use the self:: axe. EG,
'self::node()//foo', or the shorthand './/foo'.</a>
<q>I want to parse a document both as a tree, and as a stream. Can I do
this?</q>
<a>Yes, and no. There is no mechanism that directly supports this in
REXML. However, aside from writing your own traversal layer, there is a
way of doing this. To turn a tree into a stream, just turn the branch you
want to process as a stream back into a string, and re-parse it with your
preferred API. EG: pp = PullParser.new( some_element.to_s ). The other
direction is more difficult; you basically have to build a tree from the
events. REXML will have one of these builders, eventually, but it doesn't
currently exist.</a>
<q>Why is Element.elements indexed off of '1' instead of '0'?</q>
<a>Because of XPath. The XPath specification states that the index of the
first child node is '1'. Although it may be counter-intuitive to base
elements on 1, it is more undesireable to have element.elements[0] ==
element.elements[ 'node()[1]' ]. Since I can't change the XPath
specification, the result is that Element.elements[1] is the first child
element.</a>
<q>Why isn't REXML a validating parser?</q>
<a>Because validating parsers must include code that parses and interprets
DTDs. I hate DTDs. REXML supports the barest minimum of DTD parsing, and
even that isn't complete. There is DTD parsing code in the works, but I
only work on it when I'm really, really bored. Rumor has it that a
contributor is working on a DTD parser for REXML; rest assured that any
such contribution will be included with REXML as soon as it is
available.</a>
<q>I'm trying to create an ISO-8859-1 document, but when I add text to the
document it isn't being properly encoded.</q>
<a>Regardless of what the encoding of your document is, when you add text
programmatically to a REXML document you <em>must</em> ensure that you are
only adding UTF-8 to the tree. In particular, you can't add ISO-8859-1
encoded text that contains characters above 0x80 to REXML trees -- you
must convert it to UTF-8 before doing so. Luckily, this is easy:
<code>text.unpack('C*').pack('U*')</code> will do the trick. 7-bit ASCII
is identical to UTF-8, so you probably won't need to worry about this.</a>
<q>How do I get the tag name of an Element?</q>
<a>You take a look at the APIs, and notice that <code>Element</code>
includes <code>Namespace</code>. Then you click on the
<code>Namespace</code> link and look at the methods that
<code>Element</code> includes from <code>Namespace</code>. One of these is
<code>name()</code>. Another is <code>expanded_name()</code>. Yet another
is <code>prefix()</code>. Then, you email the author of rdoc and ask him
to extend rdoc so that it lists methods in the API that are included from
other files, so that you don't have to do all of that looking around for
your method.</a>
</faq>
<credits>
<p>I've had help from a number of resources; if I haven't listed you here,
it means that I just haven't gotten around to adding you, or that I'm a
dork and have forgotten. In either case, feel free to write me and
complain.</p>
<list>
<item>Mike Stok has been very active, sending not only fixes for bugs
(especially in Functions), but also by providing unit tests and making
sure REXML runs under Ruby 1.7. He also sent the most awesome hand
knitted tea cozy, with "REXML" and the Ruby knitted into it.</item>
<item>Kouhei Sutou translated the REXML API documentation to Japanese!
Links are in the API docs section of the main documentation. He has also
contributed a large number of bug reports and patches to fix bugs in
REXML.</item>
<item>Erik Terpstra heard my pleas and submitted several logos for
REXML. After sagely procrastinating for several weeks, I finally forced
my poor slave of a wife to pick one (this is what we call "delegation").
She did, with caveats; Erik quickly made the changes, and the result is
what you now see at the top of this page. He also supplied a <link
href="img/rexml_50p.png">smaller version</link> that you can include
with your projects that use REXML, if you'd like.</item>
<item>Ernest Ellingson contributed the sourcecode for turning UTF16 and
UNILE encodings into UTF8, which allowed REXML to get the 100% OASIS
valid tests rating.</item>
<item>Ian Macdonald provided me with a comprehensive, well written RPM
spec file.</item>
<item>Oliver M . Bolzer is maintaining a Debian package distribution of
REXML. He also has provided good feedback and bug reports about
namespace support.</item>
<item>Michael Granger supplied a patch for REXML that make the unit
tests pass under Ruby 1.7.</item>
<item>James Britt contributed code that makes using
Document.parse_stream easier to use by allowing it to be passed either a
Source, File, or String.</item>
<item>Tobias Reif: Numerous bug reports, and suggestions for
improvement.</item>
<item>Stefan Scholl, who provided a lot of feedback and bug reports
while I was trying to get ISO-8859-1 support working.</item>
<item>Steven E Lumos for volunteering information about XPath
particulars.</item>
<item>Fumitoshi UKAI provided some bug fixes for CData metacharacter
quoting.</item>
<item>TAKAHASHI Masayoshi, for information on UTF</item>
<item>Robert Feldt: Bug reports and suggestions/recommendations about
improving REXML. Testing is one of the most important aspects of
software development.</item>
<item><link
href="http://www.themindelectric.com/exml/index.html">Electric
XML</link>: This was, after all, the inspiration for REXML. Originally,
I was just going to do a straight port, and although REXML doesn't in
any way, shape or form resemble Electric XML, still the basic framework
and philosophy was inspired by E-XML. And I still use E-XML in my Java
projects.</item>
<item><link
href="http://www.io.com/~jimm/downloads/nqxml/index.html">NQXML</link>:
While I may complain about the NQXML API, I wrote a few applications
using it that wouldn't have been written otherwise, and it was very
useful to me. It also encouraged me to write REXML. Never complain about
free software *slap*.</item>
<item>See my <link
href="http://www.germane-software.com/~ser/technology.html">technologies
page</link> for a more comprehensive list of computer technologies that
I depend on for my day-to-day work.</item>
<item>rdoc, an excellent JavaDoc analog<footnote>When I was first
working on REXML, rdoc wasn't, IMO, very good, so I wrote API2XML.
API2XML was good enough for a while, and then there was a flurry of work
on rdoc, and it quickly surpassed API2XML in features. Since I was never
really interested in maintaining a JavaDoc analog, I stopped support of
API2XML, and am now recommending that people use
rdoc.</footnote>.</item>
<item>Many, many other people who've submitted bug reports, suggestions,
and positive feedback. You're all co-developers!</item>
</list>
</credits>
</documentation>

Просмотреть файл

@ -1,296 +0,0 @@
<?xml version="1.0" encoding="euc-jp"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN">
<html xml:lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-jp" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="author" content="U.Nakamura" />
<link rev="made" href="mailto:usa@ruby-lang.org" />
<link rel="StyleSheet" href="./ruby.css" type="text/css" />
<title>Ruby-mswin32</title>
</head>
<body>
<h1><a id="top">Ruby-mswin32</a></h1>
<p>あるいは、Windowsとの終わりなき戦い ;-(</p>
<p>[日本語 / <a href="./index_en.html">English</a>]</p>
<h2><a id="menu">▼ 目次</a></h2>
<ul>
<li><a href="#remark">注意事項</a></li>
<li><a href="#ruby">Rubyとは?</a></li>
<li><a href="#mswin32">mswin32版rubyとは?</a></li>
<li><a href="#download">バイナリ ダウンロード</a></li>
<li><a href="#install">インストール</a></li>
<li><a href="#recent">最近の出来事</a></li>
<li><a href="#link">リンク</a></li>
</ul>
<h2><a id="remark">▼ 注意事項</a></h2>
<p>このページでは、mswin32版rubyの配布と変更状況のお知らせを行っています。</p>
<p>ここは別に公式ページでもなんでもなくて、私が勝手に書いてるページです。ここで入手できるプログラム・情報(無いに等しいけど)については、各自の判断でご利用ください。<br />
問い合わせは<a href="mailto:usa@ruby-lang.org"></a>へ。間違っても他の人に迷惑をかけるようなことはしないでね。</p>
<h2><a id="ruby">▼ Rubyとは?</a></h2>
<p><a href="http://www.ruby-lang.org/ja/">Rubyのサイト</a>をご覧下さい。</p>
<h2><a id="mswin32">▼ mswin32版rubyとは?</a></h2>
<p>mswin32版rubyとは、32bit版Windows(Windows95・Windows98・WindowsMe・Windows NT・Windows 2000・WindowsXP・Windows 2003 Server、以下Windowsと表記)上で動作するRubyのバイナリの一つです。<br />
Windows上で動作するRubyとしては、現在、5種類のバイナリが存在します。これらはそれぞれmswin32版・cygwin版・mingw32版・bccwin32版・djgpp版と呼ばれています。<br />
それぞれの違いをまとめると以下のようになります(事実誤認があればお知らせください)。</p>
<dl>
<dt><a id="label:1">mswin32版</a></dt><dd>
<p>VC++でコンパイルされる。Windowsから見ればもっとも「普通」のバイナリと言えるが、反面、Rubyが持つUNIXで特徴的な機能の一部が使用できない。1.7.3以降はmingw32版と拡張ライブラリについてはバイナリ互換性がある。<br />
RUBY_PLATFORMは*-mswin32。</p>
</dd>
<dt><a id="label:2">cygwin版</a></dt><dd>
<p>gccでコンパイルされ、<a href="http://sources.redhat.com/cygwin/">cygwin</a>環境で動作する。cygwin環境がUNIXライクな環境をWindows上で構築するものであるので、当然、cygwin版rubyは一般のUNIX用のものとだいたい同じように動作する(ことが期待できる)。<br />
RUBY_PLATFORMは*-cygwin。</p>
</dd>
<dt><a id="label:3">mingw32版</a></dt><dd>
<p>gccでコンパイルされる。ソースはほとんどmswin32版と共通であり、ランタイムライブラリも共通(MSVCRT.dll)なので、動作も(おそらく)mswin32版とほぼ同じ。1.7.3以降はmswin32版と拡張ライブラリについてはバイナリ互換性がある。<br />
RUBY_PLATFORMは*-mingw32。</p>
</dd>
<dt><a id="label:4">bccwin32版</a></dt><dd>
<p>BC++でコンパイルされる。ソースはかなりの部分がmswin32版と共通ではあるが、ランタイムライブラリが異なるので、細かいところで挙動がmswin32版とは異なる(はず)。1.7以降でサポートされる。<br />
RUBY_PLATFORMは*-bccwin32。</p>
</dd>
<dt><a id="label:5">djgpp版</a></dt><dd>
<p>DJGPPでコンパイルされる。DOS用のバイナリなので、もちろんDOSでも動作する。反面、WindowsにあってDOSにない機能の多くが使えない(ネットワーク関連など)。<br />
RUBY_PLATFORMは*-msdosdjgpp。</p>
</dd>
</dl>
<p>このページでは、上記のうちmswin32版のみを扱っています。<br />
なお、cygwin版・mingw32版・djgpp版についてはわたなべさんの<a href="http://www.os.rim.or.jp/~eban/">Ruby binaries</a>から入手可能です。また、bccwin32版については小西さんの<a href="http://www001.upp.so-net.ne.jp/konishi/ruby/index.htm">Ruby</a>から入手可能です。</p>
<h2><a id="download">▼ バイナリ ダウンロード</a></h2>
<p>現在配布中の全てのバイナリはVC++ 5.0(Version 11.00.7022 for 80x86)でmakeしたものです。ruby自体に関しては、<a href="http://www.ruby-lang.org/ja/download.html">標準配布のソース</a>(または<a href="http://www.ruby-lang.org/~knu/cvsrepo-guide.html">CVS</a>のソース)からそのまま作成しています。拡張ライブラリについては各々のリンク先を参照してください。<br />
いずれのバイナリもzip形式でアーカイブされています。</p>
<p>md5sumのチェック方法ですが、例えばrubyがインストールされているなら下記のような方法があります。<br />
<code>ruby -r md5 -e "puts MD5.new(File.open('filename', 'rb').read).hexdigest"</code></p>
<h3><a id="release">Release</a></h3>
<ul>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.8.1-i386-mswin32.zip">ruby-1.8.1-i386-mswin32.zip</a> (3,764KB) <em>最新Release版</em><br />
ruby 1.8.1 (2003-12-25) [i386-mswin32]<br />
md5sum : 6bbdabeb29f1a15fa69901e87d1108ac</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.8.0-i386-mswin32.zip">ruby-1.8.0-i386-mswin32.zip</a> (2,507KB)<br />
ruby 1.8.0 (2003-08-04) [i386-mswin32]<br />
md5sum : eaf9263062429fd4f722d9a70a38a9dc</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.6.8-i586-mswin32.zip">ruby-1.6.8-i586-mswin32.zip</a> (1,964KB)<br />
ruby 1.6.8 (2002-12-24) [i586-mswin32]<br />
md5sum : f704f1248ec25b96e3e1f3070afa915e</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.6.7-i586-mswin32.zip">ruby-1.6.7-i586-mswin32.zip</a> (1,972KB)<br />
ruby 1.6.7 (2002-03-01) [i586-mswin32]<br />
md5sum : ddedc40d0fc3b0ea1d6ac74f4976bfc6</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.6.6-i586-mswin32.zip">ruby-1.6.6-i586-mswin32.zip</a> (1,944KB)<br />
ruby 1.6.6 (2001-12-26) [i586-mswin32]<br />
md5sum : 96e0d1d19a37e5e7e50ae7ce99e34636</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.6.5-i586-mswin32.zip">ruby-1.6.5-i586-mswin32.zip</a> (1,896KB)<br />
ruby 1.6.5 (2001-09-19) [i586-mswin32]<br />
md5sum : c708ae98a05df2ff8dea5a70e3791bfa</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.6.4-i586-mswin32.zip">ruby-1.6.4-i586-mswin32.zip</a> (1,821KB)<br />
ruby 1.6.4 (2001-06-04) [i586-mswin32]<br />
md5sum : cf813ca19e40be164057b3562575e4da</li>
</ul>
<h3><a id="develop">Developing versions snapshots</a></h3>
<ul>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.9.0-20040126-i386-mswin32.zip">ruby-1.9.0-20040126-i386-mswin32.zip</a> (3,849KB)<br />
ruby 1.9.0 (2004-01-26) [i386-mswin32]<br />
md5sum : fffafbf881cb6a85982220eae5a5b4f5</li>
</ul>
<h3><a id="stable">Stable versions snapshots</a></h3>
<h4><a id="stable">1.8.0</a></h4>
<ul>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.8.1-20040127-i386-mswin32.zip">ruby-1.8.1-20040127-i386-mswin32.zip</a> (3,822KB)<br />
ruby 1.8.1 (2004-01-27) [i386-mswin32]<br />
md5sum : 1fc0d5f53f0a75d0c6d1ca5d21082089</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.8.1-20031027-i386-mswin32.zip">ruby-1.8.1-20031027-i386-mswin32.zip</a> (3,075KB)<br />
ruby 1.8.1 (2003-10-27) [i386-mswin32]<br />
md5sum : 9dbdc644c529d207d0bda5d64478a5c4</li>
</ul>
<h4><a id="stable">1.6.8</a></h4>
<ul>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.6.8-20030727-i586-mswin32.zip">ruby-1.6.8-20030727-i586-mswin32.zip</a> (2,093KB)<br />
ruby 1.6.8 (2003-07-27) [i586-mswin32]<br />
md5sum : 28c3b92b162319b3d6bc99c9996cad15</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.6.8-20030515-i586-mswin32.zip">ruby-1.6.8-20030515-i586-mswin32.zip</a> (2,091KB)<br />
ruby 1.6.8 (2003-05-15) [i586-mswin32]<br />
md5sum : e5f6558de261d111add4f657ad5e345f</li>
</ul>
<h3><a id="ext">Extension libraries</a></h3>
<h4><a id="ext">1.8.0</a></h4>
<ul>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/racc-1.4.4-all-i386-mswin32-1.8.zip">racc-1.4.4-all-i386-mswin32-1.8.zip</a> (70KB)<br />
<a href="http://www.loveruby.net/en/racc.html">racc</a> 1.4.4-all (for ruby 1.8.1)<br />
md5sum : 46c4d48b714fb1ded880e7e7af456b28</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/vrswin-030906-i386-mswin32-1.8.zip">vrswin-030906-i386-mswin32-1.8.zip</a> (54KB)<br />
<a href="http://www.osk.3web.ne.jp/~nyasu/vruby/vrproject-e.html">VisualuRuby (swin)</a> 030906 (for ruby 1.8.0)<br />
md5sum : 11c2d30e2a05e9ea7e097ec7b066cedf</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/vruby-030906-i386-mswin32-1.8.zip">vruby-030906-i386-mswin32-1.8.zip</a> (96KB)<br />
<a href="http://www.osk.3web.ne.jp/~nyasu/vruby/vrproject-e.html">VisualuRuby (vruby)</a> 030906 (for ruby 1.8.0)<br />
md5sum : 77a42995e42e869932f5fb282cc297ea</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/eruby-1.0.4-i386-mswin32-1.8.zip">eruby-1.0.4-i386-mswin32-1.8.zip</a> (75KB)<br />
<a href="http://www.modruby.net/">eruby</a> 1.0.4 (for ruby 1.8.0)<br />
md5sum : de7282647f015b1d20a28dcf7c2b8715</li>
</ul>
<h4><a id="ext">1.6.8</a></h4>
<ul>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/vrswin-030521-i586-mswin32-1.6.zip">vrswin-030521-i586-mswin32-1.6.zip</a> (55KB)<br />
<a href="http://www.osk.3web.ne.jp/~nyasu/vruby/vrproject-e.html">VisualuRuby (swin)</a> 030521 (for ruby 1.6.8)<br />
md5sum : eae3284c6f79be7a119858ff9e940985</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/vruby-030517-i586-mswin32-1.6.zip">vruby-030517-i586-mswin32-1.6.zip</a> (95KB)<br />
<a href="http://www.osk.3web.ne.jp/~nyasu/vruby/vrproject-e.html">VisualuRuby (vruby)</a> 030517 (for ruby 1.6.8)<br />
md5sum : a32af752428cf3aa03000d66d8deca33</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/tmail-0.10.7-i586-mswin32-1.6.zip">tmail-0.10.7-i586-mswin32-1.6.zip</a> (160KB)<br />
<a href="http://www.loveruby.net/en/tmail.html">TMail</a> 0.10.7 (for ruby 1.6.8)<br />
md5sum : 74351ed81550dfbf3bfaf8252c316326</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/eruby-1.0.3-i586-mswin32-1.6.zip">eruby-1.0.3-i586-mswin32-1.6.zip</a> (74KB)<br />
<a href="http://www.modruby.net/">eruby</a> 1.0.3 (for ruby 1.6.8)<br />
md5sum : e05d654128422846f86ca84f55bf7bcb</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/rubywin-0.0.4.3-i586-mswin32-1.6.zip">rubywin-0.0.4.3-i586-mswin32-1.6.zip</a> (286KB)<br />
<a href="http://homepage1.nifty.com/markey/ruby/rubywin/index_e.html">RubyWin</a> 0.0.4.3 (for ruby 1.6.8)<br />
md5sum : 3f2226ef0c6e41b31c2f337f778e3e18</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/shim-20021224-i586-mswin32-1.6.zip">shim-20021224-i586-mswin32-1.6.zip</a> (138KB)<br />
<a href="http://www.ruby-lang.org/~knu/cgi-bin/cvsweb.cgi/shim/">Ruby Shim</a> 20021224 (for ruby 1.6.8)<br />
md5sum : 7ee4363195973a1df0584cb467e5ce82</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/racc-1.4.3-all-i586-mswin32-1.6.zip">racc-1.4.3-all-i586-mswin32-1.6.zip</a> (124KB)<br />
<a href="http://www.loveruby.net/en/racc.html">racc</a> 1.4.3-all (for ruby 1.6.8)<br />
md5sum : 1f093aabb464bef3074112949228a8c6</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/win32ole-0.5.2-i586-mswin32-1.6.zip">win32ole-0.5.2-i586-mswin32-1.6.zip</a> (59KB)<br />
<a href="http://homepage1.nifty.com/markey/ruby/win32ole/index_e.html">Win32OLE</a> 0.5.2 (for ruby 1.6.8)&lt;<br />
md5sum : 960f7205923a9243cff567d291b254ad</li>
<li><a href="ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ext/uconv-0.4.11-i586-mswin32-1.6.zip">uconv-0.4.11-i586-mswin32-1.6.zip</a> (110KB)<br />
<a href="http://www.yoshidam.net/Ruby.html#uconv">uconv</a> 0.4.11 (for ruby 1.6.8)<br />
md5sum : c08f3662abee8e7186283741f89b88d7</li>
</ul>
<h2><a id="install">▼ インストール</a></h2>
<p>上記のバイナリをインストールする場合は、お好みのディレクトリ(以下<code>$TOPDIR</code>と記述)に展開してください。ディレクトリ付きで圧縮されてますので、展開時にはディレクトリ付きで展開するのを忘れずに(意味がわからない人は気にしなくていいです)。<br />
展開後は、<code>$TOPDIR\bin</code><code>PATH</code>を通しておいてください。</p>
<p>なお、以下の拡張ライブラリは、この配布物に含まれない外部のライブラリに依存しています。</p>
<ul>
<li>curses.so : PDCursesに依存しています。</li>
<li>dbm.so : GDBMに依存しています。</li>
<li>gdbm.so : GDBMに依存しています。</li>
<li>iconv.so : Iconvに依存しています。</li>
<li>openssl.so : OpenSSLに依存しています。</li>
<li>readline.so : readlineに依存しています。</li>
<li>tcltklib.so : Tcl/Tkに依存しています。</li>
<li>zlib.so : Zlibに依存しています。</li>
</ul>
<p>上記のうち、PDCurses・GDBM・OpenSSL・readline・Zlibについては、<a href="http://jarp.jin.gr.jp/win32/">Porting Libraries to Win32</a>にバイナリが存在します。<br />
Iconvについては、Meadowy.orgで配布されている<a href="http://www.meadowy.org/meadow/dists/snapshot/iconv-1.8.win32.zip">iconv-1.8.win32.zip</a>を利用しています。<br />
Tcl/Tkについては、<a href="http://www.activestate.com/">ActiveState</a>で配布されている<a href="http://www.activestate.com/Products/ActiveTcl/">ActiveTcl</a>を利用しています。</p>
<h2><a id="recent">▼ 最近の出来事</a></h2>
<h3><a id="d20040127">2004-01-27</a></h3>
<p>あけましておめでとうございます。って遅いよ!</p>
<p>ruby-1.8.1-20040127とruby-1.9.0-20040126を置きました。<br />
前者は主に1.8.1リリース版で発見された不具合の修正です。後者は開発版。</p>
<h3><a id="d20031225">2003-12-25</a></h3>
<p>メリークリスマス! ruby-1.8.1がリリースされました!<br />
(previewを一つ飛ばしちゃいました、ごめんなさい...)</p>
<h3><a id="d20031206">2003-12-06</a></h3>
<p>ruby-1.8.1-preview3を置きました。思いのほか間が空いちゃいましたね。</p>
<h3><a id="d20031101">2003-11-01</a></h3>
<p>ruby-1.8.1-preview2を置きました。</p>
<h3><a id="d20031028">2003-10-28</a></h3>
<p>ruby-1.8.1-20031027を置きました。<br />
racc-1.4.4-allを置きました。</p>
<h3><a id="d20030907">2003-09-07</a></h3>
<p>eruby-1.0.4・vrswin-030906・vruby-030906を置きました。</p>
<h3><a id="d20030812">2003-08-12</a></h3>
<p>ruby-1.8.0-20030812を置きました。</p>
<p>vrswin-030811・vruby-030811を置きました。今回から置く拡張ライブラリは全て1.8用になります。</p>
<h3><a id="d20030804">2003-08-04</a></h3>
<p>ruby-1.8.0を置きました。Ruby 1.8系最初のリリースとなります。<br />
1.6系からの変更点については、<a href="ftp://ftp.ruby-lang.org/pub/ruby/1.8/changes.1.8.0">changes.1.8.0</a>などをご覧ください。</p>
<h3><a id="d20030731">2003-07-31</a></h3>
<p>ruby-1.8.0-preview6を置きました。えーと、これを含めてあと2回previewが出る模様です :)</p>
<h3><a id="d20030728">2003-07-28</a></h3>
<p>ruby-1.8.0-preview5を置きました。おそらくこれが1.8.0の最後のpreviewになるでしょう。<br />
ruby-1.6.8-20030727を置きました。</p>
<h3><a id="old">かつての出来事</a></h3>
<p><a href="./old.html">こちら</a>をどうぞ。</p>
<h2><a id="link">▼ リンク</a></h2>
<p>mswin32版に関する(と思われる)リンクです。勝手に張ってますので、不都合があれば<a href="mailto:usa@osb.att.ne.jp"></a>までご連絡ください。</p>
<ul>
<li><a href="http://www.ruby-lang.org/">Ruby Home Page</a> (<a href="http://www.ruby-lang.org/ja/">日本語</a> / <a href="http://www.ruby-lang.org/en/">English</a>)<br />
言わずとしれた、本家サイト。</li>
<li>雑記帳 (<a href="http://homepage1.nifty.com/markey/">日本語</a> / <a href="http://homepage1.nifty.com/markey/index_e.html">English</a>)<br />
助田さんのページ。<a href="http://homepage1.nifty.com/markey/ruby/rubywin/index.html">RubWin</a><a href="http://homepage1.nifty.com/markey/ruby/win32ole/index.html">Win32OLE</a>などがあります。</li>
<li><a href="http://www.moonwolf.com/ruby/">Script/Ruby</a> (日本語)<br />
MoonWolfさんのページ。Win32Moduleなどがあります。</li>
<li>ActiveScriptRuby (<a href="http://www.geocities.co.jp/SiliconValley-PaloAlto/9251/ruby/index.html">日本語</a> / <a href="http://www.geocities.co.jp/SiliconValley-PaloAlto/9251/ruby/main.html">English</a>)<br />
artonさんのページ。Windows版Rubyの未来はここにあるのかも。</li>
<li>VisualuRuby計画(仮称) (<a href="http://www.osk.3web.ne.jp/~nyasu/software/vrproject.html">日本語</a> / <a href="http://www.osk.3web.ne.jp/~nyasu/vruby/vrproject-e.html">English</a>)<br />
nyasuさんのページ。VisualuRubyなどがあります(ってこれもそのまんま)。WindowsでRubyを使うための<a href="http://www.osk.3web.ne.jp/~nyasu/software/rubyonwin.html">リンク集</a>が充実してます。ちなみに、当サイトのデザインはこちらのパクリです。多謝!</li>
<li>Ruby (<a href="http://www.yoshidam.net/Ruby_ja.html">日本語</a> / <a href="http://www.yoshidam.net/Ruby.html">English</a>)<br />
よしだむさんのページ。<a href="http://www.yoshidam.net/Ruby_ja.html#susie">Susieプラグインライブラリ</a><a href="http://www.yoshidam.net/Ruby_ja.html#rddraw">DirectDraw for Ruby</a>などがあります。</li>
<li><a href="http://homepage2.nifty.com/sakazuki/rde.html">RDE(Ruby Development Environment)</a> (日本語)<br />
sakazukiさんのページ。mswin32版ユーザなら必見です。推奨環境はartonさんとこのActiveScriptRubyですが (^^; ここの配布物を使っても問題なく動作します。</li>
</ul>
<p class="footer">
[<a href="../">戻る</a>]
</p>
<address>written by <a href="mailto:usa@ruby-lang.org">U.Nakamura</a></address>
<p class="versions">
ruby 1.9.0 (2004-01-13)<br />
ERb 2.0.4<br />
RDtool 0.6.11<br />
rublog 0.0.2
</p>
</body>
</html>

Просмотреть файл

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<evaluate>
<data>
<jumps>
<subject>
<the/>
<fox color="brown"/>
<speed category="quick"/>
</subject>
<over/>
<object>
<the/>
<dog color="unspecified"/>
<speed category="lazy"/>
</object>
</jumps>
</data>
<!-- there is one element with attribute color="brown" should this
meta-test should succeed -->
<metatest select="//@color">brown</metatest>
<!-- there is no element with attribute category="moderate" -->
<metatest select="//speed/@category">moderate</metatest>
</evaluate>

Просмотреть файл

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Fibonacci_Numbers>
<fibonacci index="0">0</fibonacci>
<fibonacci index="1">1</fibonacci>
<fibonacci index="2">1</fibonacci>
<fibonacci index="3">2</fibonacci>
<fibonacci index="4">3</fibonacci>
<fibonacci index="5">5</fibonacci>
<fibonacci index="6">8</fibonacci>
<fibonacci index="7">13</fibonacci>
<fibonacci index="8">21</fibonacci>
<fibonacci index="9">34</fibonacci>
<fibonacci index="10">55</fibonacci>
<fibonacci index="11">89</fibonacci>
<fibonacci index="12">144</fibonacci>
<fibonacci index="13">233</fibonacci>
<fibonacci index="14">377</fibonacci>
<fibonacci index="15">610</fibonacci>
<fibonacci index="16">987</fibonacci>
<fibonacci index="17">1597</fibonacci>
<fibonacci index="18">2584</fibonacci>
<fibonacci index="19">4181</fibonacci>
<fibonacci index="20">6765</fibonacci>
<fibonacci index="21">10946</fibonacci>
<fibonacci index="22">17711</fibonacci>
<fibonacci index="23">28657</fibonacci>
<fibonacci index="24">46368</fibonacci>
<fibonacci index="25">75025</fibonacci>
</Fibonacci_Numbers>

Просмотреть файл

@ -1,10 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE schema SYSTEM "foo.dtd" [
<!ATTLIST root-el
xmlns:human CDATA #FIXED "http://www.foo.com/human">
]>
<root-el xmlns="http://www.bar.com/doc"
xmlns:table="http://www.foo.com/table">
<human:leg>human leg</human:leg>
<table:leg>table leg</table:leg>
</root-el>

Просмотреть файл

@ -1,156 +0,0 @@
<form xmlns='http://www.w3.org/1999/xhtml'
enctype='application/x-www-form-urlencoded' class='rollover'
action='ModifyCampaign' method='POST'
onsubmit='return beforeRolloverSubmit(this, &apos;No campaigns selected.&apos;);'>
<a name='campaigns' shape='rect'/>
<tr bgcolor='#dbe6de'>
<th class='boxcolumn' rowspan='1' align='left' colspan='1'
width='1%'>
<script type='text/javascript'>document.write(" &lt;input
type\u003d\"checkbox\" name\u003d\"toggleAll\"
onclick\u003d\"rowToggleAll(this);\" title\u003d\"Select or
de-select all campaigns on this page\"&gt; ");</script>
</th>
<th bgcolor='#dbe6de' title='Sort by campaign name' nowrap='nowrap'
rowspan='1' align='left' colspan='1'>
<b>
<a href='CampaignSummary?campaignsummaryt=0%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Campaign Name</a>
</b>
</th>
<th bgcolor='#dbe6de' title='Sort by campaign status'
nowrap='nowrap' rowspan='1' align='left' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=1%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Current Status</a>
</th>
<th bgcolor='#dbe6de'
title='Sort by daily budget (maximum spending per day)'
nowrap='nowrap' rowspan='1' align='right' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=2%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Current Budget</a>
<span style='white-space: nowrap'>
<a href='/support/bin/answer.py?answer=6312&amp;hl=en_US'
shape='rect' id='' onclick='return helpPopUp(this);' style=''
target='google_popup'>[?]</a>
</span>
</th>
<th bgcolor='#c6d7cf' title='Sort by clicks on your ads'
nowrap='nowrap' rowspan='1' align='right' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=-3%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Clicks</a>
<a href='CampaignSummary?campaignsummaryt=-3%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
shape='rect' style='text-decoration:none;'>
<img src='/select/images/sortdown.gif' border='0' alt=''/>
</a>
</th>
<th bgcolor='#dbe6de' title='Sort by ad impressions served'
nowrap='nowrap' rowspan='1' align='right' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=4%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Impr.</a>
</th>
<th bgcolor='#dbe6de' title='Sort by CTR (clickthrough rate)'
nowrap='nowrap' rowspan='1' align='right' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=5%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>CTR</a>
</th>
<th bgcolor='#dbe6de' title='Sort by average cost per click (USD)'
nowrap='nowrap' rowspan='1' align='right' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=6%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Avg. CPC</a>
</th>
<th bgcolor='#dbe6de' class='' title='Sort by total cost (USD)'
nowrap='nowrap' rowspan='1' align='right' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=8%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Cost</a>
</th>
<th bgcolor='#dbe6de' title='Conversion Rate' nowrap='nowrap'
rowspan='1' align='right' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=11%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Conv. Rate</a>
</th>
<th bgcolor='#dbe6de' class='rightcolumn'
title='Cost per Conversion' nowrap='nowrap' rowspan='1'
align='right' colspan='1'>
<a href='CampaignSummary?campaignsummaryt=12%3Aa&amp;gsessionid=ezmXK9aaXnI#campaigns'
class='bluelink' shape='rect'>Cost/Conv.</a>
</th>
</tr>
<tr onmouseover='ron(3527627);' id='tr_3527627'
onmouseout='roff(3527627);'>
<td class='boxcolumn' rowspan='1' onclick='rowToggle(3527627);'
colspan='1'>
<input name='campaignid' type='checkbox' id='box_3527627'
value='3527627' onclick='toggleRow(this);'/>
</td>
<td rowspan='1' colspan='1'>
<a href='CampaignManagement?campaignid=3527627#a' shape='rect'>Test</a>
</td>
<td rowspan='1' colspan='1'>
<b>
<font size='-1' color='#b98b00'>Paused</font>
</b>
</td>
<td class='r' rowspan='1' colspan='1'>
<font color='#666666'>Test</font>
</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='' rowspan='1' align='right' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='rightcolumn' rowspan='1' align='right' colspan='1'>1</td>
</tr>
<tr onmouseover='ron(7680287);' id='tr_7680287'
onmouseout='roff(7680287);'>
<td class='boxcolumn' rowspan='1' onclick='rowToggle(7680287);'
colspan='1'>
<input name='campaignid' type='checkbox' id='box_7680287'
value='7680287' onclick='toggleRow(this);'/>
</td>
<td rowspan='1' colspan='1'>
<a href='CampaignManagement?campaignid=7680287#a' shape='rect'>Test</a>
</td>
<td rowspan='1' colspan='1'>
<b>
<font size='-1' color='#b98b00'>Paused</font>
</b>
</td>
<td class='r' rowspan='1' colspan='1'>
<font color='#666666'>Test</font>
</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='' rowspan='1' align='right' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='rightcolumn' rowspan='1' align='right' colspan='1'>1</td>
</tr>
<tr onmouseover='ron(6747347);' id='tr_6747347'
onmouseout='roff(6747347);'>
<td class='boxcolumn' rowspan='1' onclick='rowToggle(6747347);'
colspan='1'>
<input name='campaignid' type='checkbox' id='box_6747347'
value='6747347' onclick='toggleRow(this);'/>
</td>
<td rowspan='1' colspan='1'>
<a href='CampaignManagement?campaignid=6747347#a' shape='rect'>Test</a>
</td>
<td rowspan='1' colspan='1'>
<b>
<font size='-1' color='#b98b00'>Test</font>
</b>
</td>
<td class='r' rowspan='1' colspan='1'>
<font color='#666666'>Test</font>
</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='' rowspan='1' align='right' colspan='1'>1</td>
<td class='r' rowspan='1' colspan='1'>1</td>
<td class='rightcolumn' rowspan='1' align='right' colspan='1'>1</td>
</tr>
</form>

Просмотреть файл

@ -1,21 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo (bar)>
<!ATTLIST foo id CDATA #IMPLIED>
<!ELEMENT bar (#PCDATA|cheese)*>
<!ATTLIST bar id ID #REQUIRED>
<!ELEMENT cheese (#PCDATA)>
<!ATTLIST cheese kind ID #IMPLIED>
]>
<foo id="foobar">
<bar id="fb1">
baz
<cheese kind="edam">gouda</cheese>
baz
<cheese kind="gouda">cheddar</cheese>
baz
</bar>
</foo>

Просмотреть файл

@ -1,4 +0,0 @@
<?xml version='1.0' encoding='ISO-8859-1'?>
<booh>
<image caption='andrè is nice'/>
</booh>

Просмотреть файл

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<body><p><span></span></p><div></div></body>

Просмотреть файл

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<hostname>
<val>2</val>
<attrlist>
<hostname>CE-A</hostname>
</attrlist>
</hostname>
<hostname>
<val>1</val>
<attrlist>
<hostname>CE-B</hostname>
</attrlist>
</hostname>
</Configuration>

Просмотреть файл

@ -1,11 +0,0 @@
<?xml version="1.0"?>
<e1 xml:lang="hr">
<e2 xml:lang="en-US">
<e3/>
</e2>
<e2 xml:lang="hu">
<e3/>
<e3/>
<e3 xml:lang="es"/>
</e2>
</e1>

Просмотреть файл

@ -1,18 +0,0 @@
<programming_languages>
<language oop='yes'>
<name>
Ruby
</name>
<creator>
Yukihiro Matsumoto
</creator>
</language>
<language oop='yes'>
<name>
Python
</name>
<creator>
Guido van Rossum
</creator>
</language>
</programming_languages>

Просмотреть файл

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<message>
<header>
<service>lookupformservice</service>
<connectionid>9</connectionid>
<appid>stammdaten</appid>
<action>new</action>
</header>
<body>
<data>
<items>
<item>
<name>iteminfo</name>
<value>ELE</value>
</item>
<item>
<name>parentinfo</name>
<value>Pruefgebiete</value>
</item>
<item>
<name>id</name>
<value>1</value>
</item>
</items>
</data>
</body>
</message>

Просмотреть файл

@ -1,244 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<moreovernews>
<article code="13563275">
<url>http://c.moreover.com/click/here.pl?x13563273</url>
<headline_text>e-Commerce Operators Present Version 1.0 of the XML Standard</headline_text>
<source>StockAccess</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.stockaccess.com/index.html</document_url>
<harvest_time>Dec 24 2000 6:28AM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13560996">
<url>http://c.moreover.com/click/here.pl?x13560995</url>
<headline_text>W3C Publishes XML Protocol Requirements Document</headline_text>
<source>Xml</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.xml.com/</document_url>
<harvest_time>Dec 24 2000 12:22AM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13553522">
<url>http://c.moreover.com/click/here.pl?x13553521</url>
<headline_text>Prowler: Open Source XML-Based Content Management Framework</headline_text>
<source>Xml</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.xml.com/</document_url>
<harvest_time>Dec 23 2000 2:05PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13549014">
<url>http://c.moreover.com/click/here.pl?x13549013</url>
<headline_text>The Middleware Company Debuts Public Training Courses in Ejb, J2ee And Xml</headline_text>
<source>Java Industry Connection</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://industry.java.sun.com/javanews/more/hotnews/</document_url>
<harvest_time>Dec 23 2000 12:15PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13544468">
<url>http://c.moreover.com/click/here.pl?x13544467</url>
<headline_text>Revised Working Draft for the W3C XML Information Set</headline_text>
<source>Xml</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.xml.com/</document_url>
<harvest_time>Dec 23 2000 5:50AM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13534837">
<url>http://c.moreover.com/click/here.pl?x13534836</url>
<headline_text>XML: Its The Great Peacemaker</headline_text>
<source>ZDNet</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.zdnet.com/intweek/</document_url>
<harvest_time>Dec 22 2000 9:05PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13533486">
<url>http://c.moreover.com/click/here.pl?x13533485</url>
<headline_text>Project eL - The XML Leningrad Codex Markup Project</headline_text>
<source>Xml</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.xml.com/</document_url>
<harvest_time>Dec 22 2000 8:34PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13533489">
<url>http://c.moreover.com/click/here.pl?x13533488</url>
<headline_text>XML Linking Language (XLink) and XML Base Specifications Issued as W3C Proposed Recommenda</headline_text>
<source>Xml</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.xml.com/</document_url>
<harvest_time>Dec 22 2000 8:34PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13533493">
<url>http://c.moreover.com/click/here.pl?x13533492</url>
<headline_text>W3C Releases XHTML Basic Specification as a W3C Recommendation</headline_text>
<source>Xml</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.xml.com/</document_url>
<harvest_time>Dec 22 2000 8:34PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13521835">
<url>http://c.moreover.com/click/here.pl?x13521827</url>
<headline_text>Java, Xml And Oracle9i(TM) Make A Great Team</headline_text>
<source>Java Industry Connection</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://industry.java.sun.com/javanews/more/hotnews/</document_url>
<harvest_time>Dec 22 2000 3:21PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13512020">
<url>http://c.moreover.com/click/here.pl?x13511233</url>
<headline_text>Competing initiatives to vie for security standard</headline_text>
<source>ZDNet</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.zdnet.com/eweek/filters/news/</document_url>
<harvest_time>Dec 22 2000 10:54AM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13492401">
<url>http://c.moreover.com/click/here.pl?x13492397</url>
<headline_text>Oracle Provides Developers with Great Xml Reading This Holiday Season</headline_text>
<source>Java Industry Connection</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://industry.java.sun.com/javanews/more/hotnews/</document_url>
<harvest_time>Dec 21 2000 8:08PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13491296">
<url>http://c.moreover.com/click/here.pl?x13491292</url>
<headline_text>XML as the great peacemaker - Extensible Markup Language Accomplished The Seemingly Impossible This Year: It B</headline_text>
<source>Hospitality Net</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.hospitalitynet.org/news/list.htm?c=2000</document_url>
<harvest_time>Dec 21 2000 7:45PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13484761">
<url>http://c.moreover.com/click/here.pl?x13484758</url>
<headline_text>XML as the great peacemaker</headline_text>
<source>CNET</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://news.cnet.com/news/0-1003.html?tag=st.ne.1002.dir.1003</document_url>
<harvest_time>Dec 21 2000 4:41PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13480897">
<url>http://c.moreover.com/click/here.pl?x13480896</url>
<headline_text>COOP Switzerland Selects Mercator as Integration Platform</headline_text>
<source>Stockhouse Canada</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.stockhouse.ca/news/</document_url>
<harvest_time>Dec 21 2000 1:55PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13471024">
<url>http://c.moreover.com/click/here.pl?x13471023</url>
<headline_text>Competing XML Specs Move Toward a Union</headline_text>
<source>Internet World</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://www.internetworld.com/</document_url>
<harvest_time>Dec 21 2000 11:14AM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13452281">
<url>http://c.moreover.com/click/here.pl?x13452280</url>
<headline_text>Next-generation XHTML stripped down for handhelds</headline_text>
<source>CNET</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://news.cnet.com/news/0-1005.html?tag=st.ne.1002.dir.1005</document_url>
<harvest_time>Dec 20 2000 9:11PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13451791">
<url>http://c.moreover.com/click/here.pl?x13451789</url>
<headline_text>Xml Powers Oracle9i(TM) Dynamic Services</headline_text>
<source>Java Industry Connection</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://industry.java.sun.com/javanews/more/hotnews/</document_url>
<harvest_time>Dec 20 2000 9:05PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13442098">
<url>http://c.moreover.com/click/here.pl?x13442097</url>
<headline_text>XML DOM reference guide</headline_text>
<source>ASPWire</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://aspwire.com/</document_url>
<harvest_time>Dec 20 2000 6:26PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
<article code="13424118">
<url>http://c.moreover.com/click/here.pl?x13424117</url>
<headline_text>Repeat/Xqsite And Bowstreet Team to Deliver Integrated Xml Solutions</headline_text>
<source>Java Industry Connection</source>
<media_type>text</media_type>
<cluster>moreover...</cluster>
<tagline> </tagline>
<document_url>http://industry.java.sun.com/javanews/more/hotnews/</document_url>
<harvest_time>Dec 20 2000 9:04AM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
</moreovernews>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,18 +0,0 @@
<?xml version="1.0"?>
<foo:a xmlns:foo="http://fooNamespace/">
<b>
<c>Hello</c>
</b>
<foo:d>
<foo:e>Hey</foo:e>
</foo:d>
<bar:f xmlns:bar="http://barNamespace/">
<bar:g>Hey2</bar:g>
</bar:f>
<alias:x xmlns:alias="http://fooNamespace/">
<alias:y>Hey3</alias:y>
</alias:x>
</foo:a>

Просмотреть файл

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<nitf>
<!-- Example of markup of URLs (at the bottom of the story) -->
<head>
<meta name="ap-cycle" content="AP"/>
<meta name="ap-online-code" content="1700"/>
<meta name="ap-company" content="CO:Media Metrix Inc;TS:MMXI;IG:SVC;"/>
<meta name="ap-routing" content="ENTITLEMENTS,pfONLINE,pf1700"/>
<meta name="ap-format" content="bx"/>
<meta name="ap-category" content="f"/>
<meta name="ap-selector" content="-----"/>
<meta name="ap-transref" content="V0347"/>
<docdata>
<doc-id regsrc="AP" id-string="D76UIMO80"/>
<urgency ed-urg="7"/>
<date.issue norm="20000911T185842Z"/>
<du-key key="Napster Traffic"/>
<doc.copyright holder="(AP)"/>
</docdata>
</head>
<body>
<body.head>
<hedline>
<hl1>Use of Napster Quadruples</hl1>
</hedline>
<byline>By PETER SVENSSON
<byttl>AP Business Writer</byttl>
</byline>
<distributor>The Associated Press</distributor>
<dateline>
<location>NEW YORK</location>
</dateline>
</body.head>
<body.content>
<block>
<p>Despite the uncertain legality of the Napster online music-sharing service, the number of people
using it more than quadrupled in just five months, Media Metrix said Monday.</p>
<p>That made Napster the fastest-growing software application ever recorded by the Internet research
company.</p>
<p>From 1.1 million home users in the United States in February, the first month Media Metrix
tracked the application, Napster use rocketed to 4.9 million users in July.</p>
<p>That represents 6 percent of U.S. home PC users who have modems, said Media Metrix, which pays
people to install monitoring software on their computers.</p>
<p>It estimates total usage from a panel of about 50,000 people in the United States.</p>
<p>Napster was also used at work by 887,000 people in July, Media Metrix said.</p>
<p>Napster Inc. has been sued by the recording industry for allegedly enabling copyright
infringement. The federal government weighed in on the case Friday, saying the service is not protected
under a key copyright law, as the San Mateo, Calif., company claims.</p>
<p>Bruce Ryon, head of Media Metrix&apos;s New Media Group, said Napster was used by &quot;the full spectrum of PC users, not just the youth with time on their hands and a passion for music.&quot;</p>
<p>The Napster program allows users to copy digital music files from the hard drives of other
users over the Internet.</p>
<p>Napster Inc. said last week that 28 million people had downloaded its program. It does not reveal
its own figures for how many people actually use the software.</p>
<p>Because the program connects to the company&apos;s computers over the Internet every time
it is run, Napster Inc. can track usage exactly.</p>
<p>__</p>
<p>On the Net:</p>
<p><a href="http://www.napster.com">
http://www.napster.com</a></p>
<p><a href="http://www.mediametrix.com">
http://www.mediametrix.com</a></p>
</block>
</body.content>
</body>
</nitf>

Просмотреть файл

@ -1,18 +0,0 @@
<?xml version="1.0"?>
<numbers>
<set>
<nr>3</nr>
<nr>24</nr>
<nr>55</nr>
<nr>11</nr>
<nr>2</nr>
<nr>-3</nr>
</set>
<set>
<nr value="66"/>
<nr value="123"/>
<nr value="55"/>
<nr value="9999"/>
</set>
</numbers>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,13 +0,0 @@
<?xml version="1.0"?>
<foo>
<?cheese is tasty?>
<bar>
<baz/>
<cheese/>
<baz/>
<?toast is tasty?>
<cheese/>
<baz/>
</bar>
<?cheese is gooey?>
</foo>

Просмотреть файл

@ -1,6 +0,0 @@
<?xml version="1.0"?>
<a>
<b>foo</b>
<?toc order-by="x"?>
<c>bar</c>
</a>

Просмотреть файл

@ -1 +0,0 @@
<Project id="17" Name="dave test" Deprecated="false"><Creator User="etools" Date="10/24/00 10:54 AM"></Creator><LastModifier User="Default" Date="Fri Jun 22 14:01:54 PDT 2001"></LastModifier><Description>tool testing</Description><Purpose> </Purpose><Datasets><link name="Test data 1" idref="18"></link><link name="veg plot data" idref="21"></link></Datasets></Project>

Просмотреть файл

@ -1,2 +0,0 @@
<?xml version="1.0" ?>
<root><a>a</a><b>b</b><c><d>d</d></c></root>

Просмотреть файл

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<g>
<f a="é" />
</g>

Двоичные данные
test/rexml/data/t63-1.xml

Двоичный файл не отображается.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- generated by hnb 1.9.17 (http://hnb.sourceforge.net) -->
<!DOCTYPE tree[
<!ELEMENT tree (node*)>
<!ELEMENT data (#PCDATA)> <!-- (max 4096 bytes long) -->
<!ELEMENT node (data?,node*)>
<!ATTLIST node done (yes|no) #IMPLIED
type CDATA #IMPLIED
>]>
<tree>
<node done="no" type="todo"><data>Next_Actions</data>
<node done="no" type="todo"><data>@class</data></node>
<node done="no" type="todo"><data>@agenda</data>
<node done="yes" type="todo"><data>this is something I&apos;d like to do</data></node>
</node>
<node done="no" type="todo"><data>@dorm</data>
<node done="no" type="todo"><data>clean room</data></node>
</node>
<node done="no" type="todo"><data>@computer</data>
<node done="no" type="todo"><data>Write general makefile for cs projects</data></node>
<node done="no" type="todo"><data>Set up bash podder</data></node>
</node>
<node done="no" type="todo"><data>@errands</data>
<node done="no" type="todo"><data>Purchase geo lab book</data></node>
</node>
<node done="no" type="todo"><data>@dublin</data></node>
</node>
<node><data>projects</data></node>
</tree>

Просмотреть файл

@ -1,683 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<tests xmlns:var="http://jaxen.org/test-harness/var">
<!-- test for jaxen-24 -->
<document url="xml/jaxen24.xml">
<context select="/body/div">
<test select="preceding::*[1]" count="1"/>
<valueOf select="local-name(preceding::*[1])">span</valueOf>
</context>
<!-- jaxen-58 -->
<context select="/">
<test select="//preceding::x" count="0"/>
<test select="//following::x" count="0"/>
<test select="/descendant::*/preceding::x" count="0"/>
<test select="/descendant::node()/preceding::x" count="0"/>
</context>
</document>
<!-- test for jaxen-3 -->
<document url="xml/simple.xml">
<context select="/">
<valueOf select="string()">abd</valueOf>
</context>
<context select="/root">
<valueOf select="string()">abd</valueOf>
</context>
<context select="/root/a">
<valueOf select="string()">a</valueOf>
</context>
<context select="/root/c">
<valueOf select="string()">d</valueOf>
</context>
</document>
<!-- test for jaxen-3 -->
<document url="xml/jaxen3.xml">
<context select="/">
<test select="/Configuration/hostname/attrlist/hostname[. = 'CE-A'] " count="1"/>
</context>
</document>
<!-- parser test cases all of which should fail-->
<document url="xml/numbers.xml">
<context select="/">
<!-- repeated xpaths, jaxen-35 -->
<test exception="true" select="/numbers numbers" count="0"/>
<!-- invalid xpath, jaxen-34 -->
<test exception="true" select="/a/b[c > d]efg" count="0"/>
<!-- invalid xpath, jaxen-27 -->
<test exception="true" select="/inv/child::" count="0"/>
<!-- invalid xpath, jaxen-26 -->
<!--
<test exception="true" select="/invoice/@test[abcd" count="0"/>
<test exception="true" select="/invoice/@test[abcd > x" count="0"/>
<test exception="true" select="string-length('a" count="0"/>
<test exception="true" select="/descendant::()" count="0"/>
<test exception="true" select="(1 + 1" count="0"/>
-->
</context>
</document>
<!-- test cases for the use of underscores in names -->
<document url="xml/underscore.xml">
<context select="/">
<test select="/root/@a" count="1"/>
<test select="/root/@_a" count="1"/>
<test select="/root/b" count="1"/>
<test select="/root/_b" count="1"/>
<valueOf select="/root/@a">1</valueOf>
<valueOf select="/root/@_a">2</valueOf>
<valueOf select="/root/b">1</valueOf>
<valueOf select="/root/_b">2</valueOf>
</context>
</document>
<!-- test cases for the use of = with nodesets -->
<document url="xml/web.xml">
<context select="/">
<valueOf select="/web-app/servlet/servlet-name = 'file'">true</valueOf>
<valueOf select="/web-app/servlet/servlet-name = 'snoop'">true</valueOf>
</context>
</document>
<document url="xml/numbers.xml">
<context select="/">
<valueOf select="/numbers/set/nr = '-3'">true</valueOf>
<valueOf select="/numbers/set/nr = -3">true</valueOf>
<valueOf select="/numbers/set/nr = 24">true</valueOf>
<valueOf select="/numbers/set/nr/@value = '9999'">true</valueOf>
<valueOf select="/numbers/set/nr/@value = 9999.0">true</valueOf>
<valueOf select="/numbers/set/nr/@value = 66">true</valueOf>
</context>
</document>
<!-- test basic math... -->
<document url="xml/numbers.xml">
<context select="/">
<valueOf select="(8 * 2 + 1) = 17">true</valueOf>
<valueOf select="(1 + 8 * 2) = 17">true</valueOf>
<valueOf select="(7 - 3 + 1) = 5">true</valueOf>
<valueOf select="(8 - 4 + 5 - 6) = 3">true</valueOf>
<!-- left-assoc tests, comments show WRONG evaluation -->
<!-- 3 - 2 - 1 != 2 -->
<valueOf select="3 - 2 - 1">0</valueOf>
<!-- 8 div 4 div 2 != 4 -->
<valueOf select="8 div 4 div 2">1</valueOf>
<!-- 3 mod 5 mod 7 != 1 -->
<valueOf select="3 mod 7 mod 5">3</valueOf>
<!-- 1=(2=2) is true-->
<valueOf select="1 = 2 = 2">false</valueOf>
<!-- 2!=(3!=1) => 2!=1 => true, (2!=3)!=1 => 1!=1 => false -->
<valueOf select="2 != 3 != 1">false</valueOf>
<!-- 3 > (2 > 1) is true -->
<valueOf select="3 &gt; 2 &gt; 1">false</valueOf>
<!-- 3 >= (2 >= 2) is true -->
<valueOf select="3 &gt;= 2 &gt;= 2">false</valueOf>
<!-- 1 < (2 < 3) is false -->
<valueOf select="1 &lt; 2 &lt; 3">true</valueOf>
<!-- 0 <= (2 <= 3) is true -->
<valueOf select="2 &lt;= 2 &lt;= 3">true</valueOf>
</context>
</document>
<!-- test cases for preceding axis with different node types -->
<document url="xml/pi2.xml">
<context select="/a/c">
<test select="//processing-instruction()" count="1"/>
<test select="preceding-sibling::*" count="1"/>
<test select="preceding-sibling::node()" count="5"/>
<test select="preceding-sibling::*[1]" count="1"/>
<test select="preceding-sibling::processing-instruction()" count="1"/>
<valueOf select="preceding-sibling::processing-instruction()">order-by="x"</valueOf>
<valueOf select="preceding-sibling::*[1]">foo</valueOf>
<valueOf select="preceding-sibling::node()[2]">order-by="x"</valueOf>
</context>
</document>
<document url="xml/id.xml">
<context select="/"
var:foobar="foobar"
var:foo="foo">
<valueOf select="$foobar">foobar</valueOf>
<test select="/foo[@id=$foobar]" count="1"/>
<test select="/foo[@id='$foobar']" count="0"/>
<test select="/foo[concat($foo, 'bar')=@id]" count="1"/>
<test select="CD_Library/artist[@name=$artist]" count="0"/>
</context>
</document>
<document url="xml/id.xml">
<context select="/">
<!-- attributes have a parent: their element -->
<test select="/foo/@id/parent::foo" count="1"/>
</context>
<!-- attributes can also be used as context nodes -->
<context select="/foo/@id">
<test select="parent::foo" count="1"/>
</context>
</document>
<document url="xml/pi.xml">
<context select="/">
<test select="//processing-instruction()" count="3"/>
<test select="//processing-instruction('cheese')" count="2"/>
<test select="//processing-instruction('toast')" count="1">
<valueOf select="string()">is tasty</valueOf>
</test>
</context>
</document>
<!-- test evaluate() extension function -->
<document url="xml/evaluate.xml">
<context select="/">
<test select="evaluate('//jumps/*')" count="3"/>
<test select="evaluate('//jumps/object/dog')" count="1"/>
<test select="evaluate('//jumps/object')/evaluate" count="0"/>
<test select="evaluate('//jumps/object')/dog" count="1"/>
<test select="evaluate('//jumps/*')/dog" count="1"/>
<test select="//metatest[ evaluate(@select) = . ]" count="1"/>
</context>
</document>
<document url="xml/numbers.xml">
<context select="/numbers/set[1]">
<test select="*[-3 = .]" count="1"/>
<valueOf select="54 &lt; *">true</valueOf>
<valueOf select="55 &lt;= *">true</valueOf>
<valueOf select="69 &lt; *">false</valueOf>
<valueOf select="-2 &gt; *">true</valueOf>
<valueOf select="-3 &gt;= *">true</valueOf>
<valueOf select="-4 &gt;= *">false</valueOf>
</context>
<!-- TODO
This context should work, but needs a fixed version of saxpath to parse the right-hand side
of the greater-than expression.
<context select="/numbers/set[2]">
<valueOf select="1 &gt; nr/@value">false</valueOf>
<valueOf select="55 &gt; nr/@value">false</valueOf>
<valueOf select="55 &gt;= nr/@value">true</valueOf>
<valueOf select="1000000 &gt; nr/@value">true</valueOf>
</context>
-->
</document>
<!-- test sibling axes -->
<document url="xml/axis.xml">
<context select="/root">
<test select="preceding-sibling::*" count="0"/>
</context>
<context select="/root/a/a.3">
<test select="preceding::*" count="2"/>
</context>
<context select="/root/a/a.3">
<test select="preceding-sibling::*" count="2"/>
</context>
<context select="/">
<valueOf select="name(/root/a/a.3/preceding-sibling::*[1])">a.2</valueOf>
<valueOf select="name(/root/a/a.3/preceding-sibling::*[2])">a.1</valueOf>
</context>
<context select="/">
<valueOf select="name(/root/a/a.3/following-sibling::*[1])">a.4</valueOf>
<valueOf select="name(/root/a/a.3/following-sibling::*[2])">a.5</valueOf>
</context>
</document>
<document url="xml/web.xml">
<context select="/">
<valueOf select="/web-app/servlet[1]/servlet-name">snoop</valueOf>
<valueOf select="/web-app/servlet[1]/servlet-name/text()">snoop</valueOf>
<valueOf select="/web-app/servlet[2]/servlet-name">file</valueOf>
<valueOf select="/web-app/servlet[2]/servlet-name/text()">file</valueOf>
</context>
<context select="/web-app/servlet[1]">
<valueOf select="servlet-name">snoop</valueOf>
<valueOf select="servlet-name/text()">snoop</valueOf>
</context>
<context select="/web-app/servlet[2]/servlet-name">
<test select="preceding::*" count="3"/>
</context>
<context select="/web-app/servlet[2]/servlet-name">
<test select="following::*" count="13"/>
</context>
</document>
<!-- test name -->
<document url="xml/web.xml">
<context select="/">
<test select="*" count="1">
<valueOf select="name()">web-app</valueOf>
</test>
<!-- NOTE that the child::node() tests only work if the
XML document does not comments or PIs
-->
<test select="./*" count="1">
<valueOf select="name()">web-app</valueOf>
</test>
<test select="child::*" count="1">
<valueOf select="name()">web-app</valueOf>
</test>
<test select="/*" count="1">
<valueOf select="name()">web-app</valueOf>
</test>
<test select="/child::node()" count="1">
<valueOf select="name(.)">web-app</valueOf>
</test>
<test select="child::node()" count="1">
<valueOf select="name(.)">web-app</valueOf>
</test>
<!-- empty names -->
<valueOf select="name()"></valueOf>
<valueOf select="name(.)"></valueOf>
<valueOf select="name(parent::*)"></valueOf>
<valueOf select="name(/)"></valueOf>
<valueOf select="name(/.)"></valueOf>
<valueOf select="name(/self::node())"></valueOf>
<!-- name of root elemet -->
<valueOf select="name(node())">web-app</valueOf>
<valueOf select="name(/node())">web-app</valueOf>
<valueOf select="name(/*)">web-app</valueOf>
<valueOf select="name(/child::*)">web-app</valueOf>
<valueOf select="name(/child::node())">web-app</valueOf>
<valueOf select="name(/child::node())">web-app</valueOf>
<valueOf select="name(child::node())">web-app</valueOf>
<valueOf select="name(./*)">web-app</valueOf>
<valueOf select="name(*)">web-app</valueOf>
</context>
<context select="/*">
<!-- empty names -->
<valueOf select="name(..)"></valueOf>
<valueOf select="name(parent::node())"></valueOf>
<valueOf select="name(parent::*)"></valueOf>
<!-- name of root elemet -->
<valueOf select="name()">web-app</valueOf>
<valueOf select="name(.)">web-app</valueOf>
<valueOf select="name(../*)">web-app</valueOf>
<valueOf select="name(../child::node())">web-app</valueOf>
</context>
</document>
<!-- test predicates -->
<document url="xml/nitf.xml">
<context select="/nitf/head/docdata">
<test select="doc-id[@regsrc='AP' and @id-string='D76UIMO80']" count="1"/>
</context>
<context select="/nitf/head">
<test select="meta[@name='ap-cycle']" count="1"/>
<test select="meta[@content='AP']" count="1"/>
<test select="meta[@name and @content]" count="8"/>
<test select="meta[@name='ap-cycle' and @content='AP']" count="1"/>
<test select="meta[@name != 'ap-cycle']" count="7"/>
</context>
<context select="/">
<test select="/nitf/head/meta[@name='ap-cycle']" count="1"/>
<test select="/nitf/head/meta[@content='AP']" count="1"/>
<test select="/nitf/head/meta[@name and @content]" count="8"/>
<test select="/nitf/head/meta[@name='ap-cycle' and @content='AP']" count="1"/>
<test select="/nitf/head/meta[@name != 'ap-cycle']" count="7"/>
</context>
</document>
<document url="xml/moreover.xml">
<context select="/">
<test select="/child::node()" count="1"/>
<test select="/*" count="1"/>
<test select="/*/article" count="20"/>
<test select="//*" count="221"/>
<test select="//*[local-name()='article']" count="20"/>
<test select="//article" count="20"/>
<test select="/*/*[@code]" count="20"/>
<test select="/moreovernews/article[@code='13563275']" count="1"/>
<test select="/moreovernews/article[@code='13563275']">
<valueOf select="url">http://c.moreover.com/click/here.pl?x13563273</valueOf>
</test>
<test select="/*/article[@code='13563275']">
<valueOf select="url">http://c.moreover.com/click/here.pl?x13563273</valueOf>
</test>
<test select="//article[@code='13563275']">
<valueOf select="url">http://c.moreover.com/click/here.pl?x13563273</valueOf>
</test>
<test select="//*[@code='13563275']">
<valueOf select="url">http://c.moreover.com/click/here.pl?x13563273</valueOf>
</test>
<test select="/child::node()/child::node()[@code='13563275']">
<valueOf select="url">http://c.moreover.com/click/here.pl?x13563273</valueOf>
</test>
<test select="/*/*[@code='13563275']">
<valueOf select="url">http://c.moreover.com/click/here.pl?x13563273</valueOf>
</test>
</context>
</document>
<!-- test other node types-->
<document url="xml/contents.xml">
<context select="/">
<test select="processing-instruction()" count="3"/>
<test select="/processing-instruction()" count="3"/>
<test select="/comment()" count="1"/>
<test select="comment()" count="1"/>
<test select="/child::node()/comment()" count="2"/>
<test select="/*/comment()" count="2"/>
<test select="//comment()" count="3"/>
</context>
</document>
<!-- test positioning -->
<document url="xml/fibo.xml">
<context select="/">
<test select="/*/fibonacci[position() &lt; 10]" count="9"/>
<valueOf select="sum(//fibonacci)">196417</valueOf>
<valueOf select="sum(//fibonacci/@index)">325</valueOf>
<valueOf select="/*/fibonacci[2]">1</valueOf>
<valueOf select="/*/fibonacci[ count(/*/fibonacci) ]">75025</valueOf>
<valueOf select="/*/fibonacci[ count(/*/fibonacci) - 1 ]">46368</valueOf>
</context>
</document>
<!-- test number functions -->
<!-- test Axes -->
<document url="xml/web.xml">
<context select="/">
<test select="descendant-or-self::*" count="19"/>
<test select="descendant::*" count="19"/>
<test select="/descendant::*" count="19"/>
<test select="/descendant-or-self::*" count="19"/>
<test select="/descendant::servlet" count="2"/>
<test select="/descendant-or-self::servlet" count="2"/>
<test select="descendant-or-self::servlet" count="2"/>
<test select="descendant::servlet" count="2"/>
<test select="/*/servlet" count="2"/>
<valueOf select="count(/*/servlet)">2</valueOf>
<test select="//servlet" count="2"/>
<valueOf select="count(//servlet)">2</valueOf>
</context>
<context select="/web-app">
<test select="/descendant::servlet" count="2"/>
<test select="/descendant-or-self::servlet" count="2"/>
<test select="descendant-or-self::servlet" count="2"/>
<test select="descendant::servlet" count="2"/>
</context>
</document>
<document url="xml/much_ado.xml">
<context select="/">
<test select="/descendant::ACT" count="5"/>
<test select="descendant::ACT" count="5"/>
<valueOf select="/PLAY/TITLE">Much Ado about Nothing</valueOf>
<valueOf select="2+2">4</valueOf>
<valueOf select="5 * 4 + 1">21</valueOf>
<valueOf select="count(descendant::ACT)">5</valueOf>
<valueOf select="10 + count(descendant::ACT) * 5">35</valueOf>
<valueOf select="(10 + count(descendant::ACT)) * 5">75</valueOf>
</context>
<context select="/PLAY/ACT[2]/SCENE[1]">
<test select="/descendant::ACT" count="5"/>
<test select="../../descendant::ACT" count="5"/>
<test select="/PLAY/ACT[2]/SCENE[1]/descendant::SPEAKER" count="141"/>
<test select="descendant::SPEAKER" count="141"/>
<valueOf select="count(descendant::*)+1">646</valueOf>
<valueOf select="count(descendant::SPEAKER)+1">142</valueOf>
<valueOf select="count(ancestor::*)">2</valueOf>
<valueOf select="count(ancestor::PLAY)">1</valueOf>
<valueOf select="count(ancestor-or-self::*)">3</valueOf>
<valueOf select="count(ancestor-or-self::PLAY)">1</valueOf>
<valueOf select="5+count(ancestor::*)-1">6</valueOf>
</context>
<context select="/">
<!-- Test correct predicate application -->
<valueOf select="count(/PLAY/ACT/SCENE[1])">5</valueOf>
</context>
</document>
<!-- test axis node ordering -->
<document url="xml/web.xml">
<context select="/">
<!-- Reported as Jira issue JAXEN-24 -->
<test select="//servlet-mapping/preceding::*[1][name()='description']" count="1"/>
<test select="/web-app/servlet//description/following::*[1][name()='servlet-mapping']" count="1"/>
<test select="/web-app/servlet//description/following::*[2][name()='servlet-name']" count="1"/>
</context>
</document>
<!-- test document function -->
<document url="xml/text.xml">
<context select="/">
<test select="document('xml/web.xml')" count="1">
<valueOf select="/web-app/servlet[1]/servlet-name">snoop</valueOf>
<valueOf select="/web-app/servlet[1]/servlet-name/text()">snoop</valueOf>
</test>
<valueOf select="document('xml/web.xml')/web-app/servlet[1]/servlet-name">snoop</valueOf>
</context>
<!-- Test to check if the context changes when an extension function is used.
First test is an example, second is the actual test.
-->
<context select="/foo/bar/cheese[1]">
<valueOf select="concat(./@id,'foo',@id)">3foo3</valueOf>
<valueOf select="concat(./@id,document('xml/web.xml')/web-app/servlet[1]/servlet-name,./@id)">3snoop3</valueOf>
</context>
</document>
<document url="xml/message.xml">
<context select="/">
<valueOf select="/message/body/data/items/item[name/text()='parentinfo']/value">Pruefgebiete</valueOf>
<valueOf select="document('xml/message.xml')/message/body/data/items/item[name/text()='parentinfo']/value">Pruefgebiete</valueOf>
</context>
</document>
<document url="xml/simple.xml">
<!-- test behaviour of AbsoluteLocationPath -->
<context select="/root/a">
<valueOf select="concat( ., /root/b )">ab</valueOf>
<valueOf select="concat( ../b, . )">ba</valueOf>
<valueOf select="concat( /root/b, . )">ba</valueOf>
<valueOf select="concat( /root/c/d, ../b )">db</valueOf>
</context>
<!-- test the translate() function -->
<context select="/">
<valueOf select="translate( '', '', '' )"></valueOf>
<valueOf select="translate( 'abcd', '', '' )">abcd</valueOf>
<valueOf select="translate( 'abcd', 'abcd', 'abcd' )">abcd</valueOf>
<valueOf select="translate( 'abcd', 'dcba', 'dcba' )">abcd</valueOf>
<valueOf select="translate( 'abcd', 'abcd', 'dcba' )">dcba</valueOf>
<valueOf select="translate( 'abcd', 'abcd', 'ab' )">ab</valueOf>
<valueOf select="translate( 'abcd', 'cdab', 'cd' )">cd</valueOf>
<valueOf select="translate( 'abcd', 'acbd', 'xy' )">xy</valueOf>
<valueOf select="translate( 'abcd', 'abcdb', 'abcdb' )">abcd</valueOf>
<valueOf select="translate( 'abcd', 'abcd', 'abcdb' )">abcd</valueOf>
</context>
<context select="/">
<valueOf select="substring('12345', 1.5, 2.6)">234</valueOf>
<valueOf select="substring('12345', 0, 3)">12</valueOf>
<valueOf select="substring('12345', 0 div 0, 3)"></valueOf>
<valueOf select="substring('12345', 1, 0 div 0)"></valueOf>
<valueOf select="substring('12345', -42, 1 div 0)">12345</valueOf>
<valueOf select="substring('12345', -1 div 0, 1 div 0)"></valueOf>
<valueOf select="substring('12345', 3)">345</valueOf>
<valueOf select="substring('12345',1,15)">12345</valueOf>
</context>
<!-- Some tests for the normalize-space() function -->
<context select="/">
<valueOf select="normalize-space(' abc ')">abc</valueOf>
<valueOf select="normalize-space(' a b c ')">a b c</valueOf>
<valueOf select="normalize-space(' a &#x0d; b &#x0a; c ')">a b c</valueOf>
<!-- Next test case addresses issue JAXEN-22 -->
<valueOf select="normalize-space(' ')"></valueOf>
<!-- Next test case addresses issue JAXEN-29 -->
<valueOf select="normalize-space('')"></valueOf>
</context>
</document>
<!-- test cases for String extension functions -->
<document url="xml/web.xml">
<context select="/web-app/servlet[1]">
<valueOf select="upper-case( servlet-class )">SNOOPSERVLET</valueOf>
<valueOf select="lower-case( servlet-class )">snoopservlet</valueOf>
<valueOf select="upper-case( servlet-class, 'fr' )">SNOOPSERVLET</valueOf>
<valueOf select="upper-case( servlet-class, 'fr-CA' )">SNOOPSERVLET</valueOf>
<valueOf select="upper-case( servlet-class, 'es-ES-Traditional_WIN' )">SNOOPSERVLET</valueOf>
<valueOf select="ends-with( servlet-class, 'Servlet' )">true</valueOf>
<valueOf select="ends-with( servlet-class, 'S' )">false</valueOf>
</context>
</document>
<!-- test cases for the lang() function -->
<document url="xml/lang.xml">
<context select="/">
<test select="/e1/e2[lang('hr')]" count="0"/>
<test select="/e1/e2/e3[lang('en')]" count="1"/>
<test select="/e1/e2/e3[lang('en-US')]" count="1"/>
<test select="/e1/e2/e3[lang('en-GB')]" count="0"/>
<test select="/e1/e2/e3[lang('hu')]" count="2"/>
<test select="/e1/e2/e3[lang('hu-HU')]" count="0"/>
<test select="/e1/e2/e3[lang('es')]" count="1"/>
<test select="/e1/e2/e3[lang('es-BR')]" count="0"/>
</context>
</document>
<!-- test namespace -->
<document url="xml/namespaces.xml">
<context select="/"
xmlns:foo="http://fooNamespace/"
xmlns:voo="http://fooNamespace/"
xmlns:bar="http://barNamespace/"
xmlns:alias="http://fooNamespace/">
<test select="/*" count="1"/>
<test select="/foo:a" count="1"/>
<test select="/foo:a/b" count="1"/>
<test select="/voo:a/b/c" count="1"/>
<test select="/voo:a/bar:f" count="1"/>
<test select="/*[namespace-uri()='http://fooNamespace/' and local-name()='a']" count="1"/>
<test select="/*[local-name()='a' and namespace-uri()='http://fooNamespace/']/*[local-name()='x' and namespace-uri()='http://fooNamespace/']" count="1"/>
<test select="/*[local-name()='a' and namespace-uri()='http://fooNamespace/']/*[local-name()='x' and namespace-uri()='http://fooNamespace/']/*[local-name()='y' and namespace-uri()='http://fooNamespace/']" count="1"/>
</context>
<!-- the prefix here and in the document have no relation; it's their
namespace-uri binding that counts -->
<context select="/" xmlns:foo="http://somethingElse/">
<test select="/foo:a/b/c" count="0"/>
</context>
<context select="/"
xmlns:foo="http://fooNamespace/"
xmlns:bar="http://barNamespace/"
xmlns:alias="http://fooNamespace/">
<valueOf select="/foo:a/b/c">Hello</valueOf>
<valueOf select="/foo:a/foo:d/foo:e">Hey</valueOf>
<valueOf select="/foo:a/alias:x/alias:y">Hey3</valueOf>
<valueOf select="/foo:a/foo:x/foo:y">Hey3</valueOf>
<valueOf select="/*[local-name()='a' and namespace-uri()='http://fooNamespace/']/*[local-name()='x' and namespace-uri()='http://fooNamespace/']/*[local-name()='y' and namespace-uri()='http://fooNamespace/']">Hey3</valueOf>
</context>
</document>
<document url="xml/defaultNamespace.xml">
<context select="/">
<!-- NOTE: /a/b/c selects elements in no namespace only! -->
<test select="/a/b/c" count="0"/>
<!--
The following test uses an unbound prefix 'x' and should throw an exception.
Addresses issue JAXEN-18.
Turns out this isn't really tested as the test didn't fail when the exception wasn't thrown.
<test select="/x:a/x:b/x:c" count="0" exception="true"/>
-->
</context>
<context select="/"
xmlns:dummy="http://dummyNamespace/">
<test select="/dummy:a/dummy:b/dummy:c" count="1"/>
</context>
</document>
<document url="xml/text.xml">
<context select="/">
<test select="/foo/bar/text()" count="3"/>
<valueOf select="normalize-space(/foo/bar/text())">baz</valueOf>
</context>
</document>
<document url="xml/testNamespaces.xml">
<context select="/">
<!-- the root is not an element, so no namespaces -->
<test select="namespace::*" count="0" debug="off"/>
<test select="/namespace::*" count="0" debug="off"/>
<test select="/Template/Application1/namespace::*" count="3" debug="off"/>
<test select="/Template/Application2/namespace::*" count="3" debug="off"/>
<test select="//namespace::*" count="25" debug="off"/>
</context>
<!--
<context select="/Template/Application1">
<test select="namespace::*" count="3" debug="off"/>
<test select="/namespace::*" count="0" debug="off"/>
<test select="/Template/Application1/namespace::*" count="3" debug="off"/>
<test select="/Template/Application2/namespace::*" count="3" debug="off"/>
<test select="//namespace::*" count="25" debug="off"/>
<test select="//namespace::xplt" count="8" debug="off"/>
<test xmlns:somethingelse="http://www.xxxx.com/"
select="//namespace::somethingelse" count="0" debug="off"/>
</context>
-->
</document>
<document url="xml/testNamespaces.xml">
<context select="/">
<!-- namespace nodes have their element as their parent -->
<test select="/Template/namespace::xml/parent::Template" count="1"/>
</context>
<!-- namespace nodes can also be used as context nodes -->
<context select="/Template/namespace::xml">
<test select="parent::Template" count="1"/>
</context>
</document>
</tests>

Просмотреть файл

@ -1,369 +0,0 @@
<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:var="http://jaxen.org/test-harness/var">
<!-- this is what I used to generate XPathTestBase. After generating I fixed the illegal strings (its quicker
than fixing the xsl for that few errors) and reformatted the code. Its unlikely this code will be needed
again, its just in cvs for completeness -->
<output method="text"/>
<template match="/">
<text>
/*
* $Header: /home/projects/jaxen/scm/jaxen/src/java/test/org/jaxen/XPathTestBase.java,v 1.32 2005/06/15 23:52:40 bewins Exp $
* $Revision: 1.32 $
* $Date: 2005/06/15 23:52:40 $
*
* ====================================================================
*
* Copyright (C) 2000-2002 bob mcwhirter &amp; James Strachan.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions, and the disclaimer that follows
* these conditions in the documentation and/or other materials
* provided with the distribution.
*
* 3. The name "Jaxen" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact license@jaxen.org.
*
* 4. Products derived from this software may not be called "Jaxen", nor
* may "Jaxen" appear in their name, without prior written permission
* from the Jaxen Project Management (pm@jaxen.org).
*
* In addition, we request (but do not require) that you include in the
* end-user documentation provided with the redistribution and/or in the
* software itself an acknowledgement equivalent to the following:
* "This product includes software developed by the
* Jaxen Project (http://www.jaxen.org/)."
* Alternatively, the acknowledgment may be graphical using the logos
* available at http://www.jaxen.org/
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE Jaxen AUTHORS OR THE PROJECT
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ====================================================================
* This software consists of voluntary contributions made by many
* individuals on behalf of the Jaxen Project and was originally
* created by bob mcwhirter &lt;bob@werken.com> and
* James Strachan &lt;jstrachan@apache.org>. For more information on the
* Jaxen Project, please see &lt;http://www.jaxen.org/>.
*
* $Id: XPathTestBase.java,v 1.32 2005/06/15 23:52:40 bewins Exp $
*/
package org.jaxen;
import junit.framework.TestCase;
import org.jaxen.function.StringFunction;
import org.jaxen.saxpath.helpers.XPathReaderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public abstract class XPathTestBase extends TestCase
{
protected static String VAR_URI = "http://jaxen.org/test-harness/var";
protected static String TESTS_XML = "xml/test/tests.xml";
protected static boolean verbose = true;
protected static boolean debug = true;
private ContextSupport contextSupport;
public XPathTestBase(String name)
{
super( name );
}
public void setUp() throws ParserConfigurationException
{
this.contextSupport = null;
System.setProperty( XPathReaderFactory.DRIVER_PROPERTY,
"" );
log( "-----------------------------" );
}
public void log(String text)
{
log( verbose,
text );
}
public void log(boolean actualVerbose,
String text)
{
if ( ! actualVerbose )
{
return;
}
System.out.println( text );
}
protected void assertCountXPath(int expectedSize, Object context, String xpathStr) throws JaxenException {
try
{
assertCountXPath2(expectedSize, context, xpathStr);
}
catch (UnsupportedAxisException e)
{
log ( debug,
" ## SKIPPED -- Unsupported Axis" );
}
}
protected Object assertCountXPath2(int expectedSize, Object context, String xpathStr) throws JaxenException {
log ( debug,
" Select :: " + xpathStr );
BaseXPath xpath = new BaseXPath( xpathStr );
List results = xpath.selectNodes( getContext( context ) );
log ( debug,
" Expected Size :: " + expectedSize );
log ( debug,
" Result Size :: " + results.size() );
if ( expectedSize != results.size() )
{
log ( debug,
" ## FAILED" );
log ( debug,
" ## xpath: " + xpath + " = " + xpath.debug() );
Iterator resultIter = results.iterator();
while ( resultIter.hasNext() )
{
log ( debug,
" --> " + resultIter.next() );
}
}
assertEquals( xpathStr,
expectedSize,
results.size() );
if (expectedSize > 0) {
return results.get(0);
}
return null;
}
protected void assertInvalidXPath(Object context, String xpathStr) throws JaxenException {
try
{
log ( debug,
" Select :: " + xpathStr );
BaseXPath xpath = new BaseXPath( xpathStr );
List results = xpath.selectNodes( getContext( context ) );
log ( debug,
" Result Size :: " + results.size() );
fail("An exception was expected.");
}
catch (UnsupportedAxisException e)
{
log ( debug,
" ## SKIPPED -- Unsupported Axis" );
}
catch (JaxenException e) {
log (debug, " Caught expected exception "+e.getMessage());
}
}
protected void assertValueOfXPath(String expected, Object context, String xpathStr) throws JaxenException {
try
{
BaseXPath xpath = new BaseXPath( xpathStr );
Object node = xpath.evaluate( getContext( context ) );
String result = StringFunction.evaluate( node,
getNavigator() );
log ( debug,
" Select :: " + xpathStr );
log ( debug,
" Expected :: " + expected );
log ( debug,
" Result :: " + result );
if ( ! expected.equals( result ) )
{
log ( debug,
" ## FAILED" );
log ( debug,
" ## xpath: " + xpath + " = " + xpath.debug() );
}
assertEquals( xpathStr,
expected,
result );
}
catch (UnsupportedAxisException e)
{
log ( debug,
" ## SKIPPED -- Unsupported Axis " );
}
}
protected Context getContext(Object contextNode)
{
Context context = new Context( getContextSupport() );
List list = new ArrayList( 1 );
list.add( contextNode );
context.setNodeSet( list );
return context;
}
public ContextSupport getContextSupport()
{
if ( this.contextSupport == null )
{
this.contextSupport = new ContextSupport( new SimpleNamespaceContext(),
XPathFunctionContext.getInstance(),
new SimpleVariableContext(),
getNavigator() );
}
return this.contextSupport;
}
public abstract Navigator getNavigator();
public abstract Object getDocument(String url) throws Exception;
public void testGetNodeType() throws FunctionCallException, UnsupportedAxisException
{
Navigator nav = getNavigator();
Object document = nav.getDocument("xml/testNamespaces.xml");
int count = 0;
Iterator descendantOrSelfAxisIterator = nav.getDescendantOrSelfAxisIterator(document);
while (descendantOrSelfAxisIterator.hasNext()) {
Object node = descendantOrSelfAxisIterator.next();
Iterator namespaceAxisIterator = nav.getNamespaceAxisIterator(node);
while (namespaceAxisIterator.hasNext()) {
count++;
assertEquals("Node type mismatch", Pattern.NAMESPACE_NODE, nav.getNodeType(namespaceAxisIterator.next()));
}
}
assertEquals(25, count);
}
</text>
<apply-templates select="node()|@*"/>
<text>
}
</text>
</template>
<template match="context">
<text>
public void test</text><value-of select="generate-id()"/><text>() throws JaxenException {
Navigator nav = getNavigator();
String url = "</text><value-of select="../@url"/><text>";
log( "Document [" + url + "]" );
Object document = nav.getDocument(url);
XPath contextpath = new BaseXPath("</text><value-of select="@select"/><text>", nav);
log( "Initial Context :: " + contextpath );
List list = contextpath.selectNodes(document);
</text>
<if test="count(namespace::*) > count(../namespace::*)">
<text>
SimpleNamespaceContext nsContext = new SimpleNamespaceContext();</text>
<for-each select="namespace::*[local-name() != 'var' and local-name() != 'xml']">
<text>
nsContext.addNamespace( "</text><value-of select="local-name()"/><text>", "</text><value-of select="."/><text>" );</text>
</for-each>
<text>
getContextSupport().setNamespaceContext( nsContext );</text>
</if>
<if test="@*[namespace-uri() = 'http://jaxen.org/test-harness/var']">
<text>
SimpleVariableContext varContext = new SimpleVariableContext();</text>
<for-each select="@*[namespace-uri() = 'http://jaxen.org/test-harness/var']">
<text>
varContext.setVariableValue(null, "</text><value-of select="local-name()"/><text>", "</text><value-of select="."/><text>" );</text>
</for-each>
<text>
getContextSupport().setVariableContext( varContext );</text>
</if>
<text>
Iterator iter = list.iterator();
while (iter.hasNext()) {
Object context = iter.next();</text>
<apply-templates select="node()|@*"/>
<text>
}
}</text>
</template>
<template match="test[@exception]">
<text>
assertInvalidXPath(context, "</text><value-of select='@select'/><text>");</text>
</template>
<template match="test[valueOf]">
<choose>
<when test="@count">
<text>
try
{
Object result = assertCountXPath2(</text><value-of select="@count"/><text>, context, "</text><value-of select="@select"/><text>");</text>
<for-each select="valueOf">
<text>
assertValueOfXPath("</text><value-of select="."/><text>", result, "</text><value-of select="@select"/><text>");</text>
</for-each>
<text>
}
catch (UnsupportedAxisException e)
{
log ( debug, " ## SKIPPED -- Unsupported Axis" );
}</text>
</when>
<otherwise>
<text>
try
{
BaseXPath xpath = new BaseXPath( "</text><value-of select="@select"/><text>" );
List results = xpath.selectNodes( getContext( context ) );
Object result = results.get(0);</text>
<for-each select="valueOf">
<text>
assertValueOfXPath("</text><value-of select="."/><text>", result, "</text><value-of select="@select"/><text>");</text>
</for-each>
<text>
}
catch (UnsupportedAxisException e)
{
log ( debug, " ## SKIPPED -- Unsupported Axis" );
}</text>
</otherwise>
</choose>
</template>
<template match="test">
<text>
assertCountXPath(</text><value-of select="@count"/><text>, context, "</text><value-of select="@select"/><text>");</text>
</template>
<template match="valueOf">
<text>
assertValueOfXPath("</text><value-of select="."/>", context, "<value-of select="@select"/><text>");</text>
</template>
<template match="comment()"><text>
/*</text><value-of select="."/><text>
*/</text>
</template>
<template match="node()|@*"><apply-templates select="node()|@*"/></template>
</stylesheet>

Просмотреть файл

@ -1,22 +0,0 @@
<Template>
<Application1 xmlns:xplt="http://www.xxxx.com/"
xmlns:xpl="http://www.xxxx.com/"
version="3.0"
randomAttribute="foo"
>
<xpl:insertText/>
<xplt:anyElement>
<Name/>
</xplt:anyElement>
</Application1>
<Application2 xmlns:xplt="http://www.xxxx.com/"
xmlns:xpl="http://www.xxxx.com/"
version="3.0"
>
<xpl:insertText/>
<xplt:anyElement>
<Name/>
</xplt:anyElement>
</Application2>
</Template>

Просмотреть файл

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN"
"http://my.netscape.com/publish/formats/rss-0.91.dtd">
<rss version="0.91">
<channel>
<title>xmlhack</title>
<link>http://www.xmlhack.com</link>
<description>Developer news from the XML community</description>
<language>en-us</language>
<copyright>Copyright 1999-2001, xmlhack team.</copyright>
<managingEditor>editor@xmlhack.com</managingEditor>
<webMaster>webmaster@xmlhack.com</webMaster>
<image>
<title>xmlhack</title>
<url>http://www.xmlhack.com/images/mynetscape88.gif</url>
<link>http://www.xmlhack.com</link>
<width>88</width>
<height>31</height>
<description>News, opinions, tips and issues concerning XML development</description>
</image>
<item x='0'>
<title>Experimental non-XML syntax for RELAX NG</title>
<link>http://www.xmlhack.com/read.php?item=1343</link>
<description>
James Clark has announced the release of an experimental non-XML syntax for RELAX
NG and a Java translator implementation that converts
instances of the syntax into RELAX NG's XML syntax.
</description>
<category>Schemas</category>
</item>
<item x='1'>
<title>Long-awaited entity-resolver Java classes finally released</title>
<link>http://www.xmlhack.com/read.php?item=1342</link>
<description>Norman Walsh has
announced the release of SAX entityResolver() and JAXP
URIResolver() Java
classes he wrote to implement the OASIS XML Catalogs
Committee Specification (in addition to the TR9401 and
Apache XCatalogs specifications).
</description>
<category>SGML/XML</category>
<category>Java</category>
</item>
<item x='3'>
<title>Beepcore-C framework released</title>
<link>http://www.xmlhack.com/read.php?item=1341</link>
<description>Invisible Worlds have announced the publication of Beepcore-C, an implementation of the BEEP framework written in C.</description>
<category>Protocols</category>
<category>C++</category>
</item>
<item>
<title>SVG and XSL-FO by example</title>
<link>http://www.xmlhack.com/read.php?item=1340</link>
<description>Jirka Jirat has announced the
addition of an XSL-FO and SVG examples repository to the Zvon developer
reference site.</description>
<category>SVG</category>
<category>XSL-FO</category>
</item>
</channel>
</rss>

Просмотреть файл

@ -1,10 +0,0 @@
<?xml version="1.0"?>
<foo>
<bar>
baz
<cheese id="3"/>
baz
<cheese/>
baz
</bar>
</foo>

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,590 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Rev 1.05
Changed the <gram> element name to <pos>
Added the g_gend attribute
moved the s_inf element
-->
<!-- Rev 1.04
Changes:
Rename the project "JMdict" and add the g_lang attribute to the
<gloss> entity - 08 May 1999
Moved the <gram>, <field> and <misc> elements down to be in the
<sense> region, as suggested by Chris Czeyka. I have also tidied up
some of the "*" as he suggested. - 27 May 2000
Added the re_nokanji element - Sep 2003.
-->
<!DOCTYPE JMdict [
<!ELEMENT JMdict (entry*)>
<!-- -->
<!ELEMENT entry (ent_seq, k_ele*, r_ele+, info*, sense+)>
<!-- Entries consist of kanji elements, reading elements,
general information and sense elements. Each entry must have at
least one reading element and one sense element. Others are optional.
-->
<!ELEMENT ent_seq (#PCDATA)>
<!-- A unique numeric sequence number for each entry
-->
<!ELEMENT k_ele (keb, ke_inf*, ke_pri*)>
<!-- The kanji element, or in its absence, the reading element, is
the defining component of each entry.
The overwhelming majority of entries will have a single kanji
element associated with a word in Japanese. Where there are
multiple kanji elements within an entry, they will be orthographical
variants of the same word, either using variations in okurigana, or
alternative and equivalent kanji. Common "mis-spellings" may be
included, provided they are associated with appropriate information
fields. Synonyms are not included; they may be indicated in the
cross-reference field associated with the sense element.
-->
<!ELEMENT keb (#PCDATA)>
<!-- This element will contain a word or short phrase in Japanese
which is written using at least one kanji. The valid characters are
kanji, kana, related characters such as chouon and kurikaeshi, and
in exceptional cases, letters from other alphabets.
-->
<!ELEMENT ke_inf (#PCDATA)>
<!-- This is a coded information field related specifically to the
orthography of the keb, and will typically indicate some unusual
aspect, such as okurigana irregularity.
-->
<!ELEMENT ke_pri (#PCDATA)>
<!-- This and the equivalent re_pri field are provided to record
information about the relative priority of the entry, and consist
of codes indicating the word appears in various references which
can be taken as an indication of the frequency with which the word
is used. This field is intended for use either by applications which
want to concentrate on entries of a particular priority, or to
generate subset files.
The current values in this field are:
- news1/2: appears in the "wordfreq" file compiled by Alexandre Girardi
from the Mainichi Shimbun. (See the Monash ftp archive for a copy.)
Words in the first 12,000 in that file are marked "news1" and words
in the second 12,000 are marked "news2".
- ichi1/2: appears in the "Ichimango goi bunruishuu", Senmon Kyouiku
Publishing, Tokyo, 1998.
- spec1 and spec2: a small number of words use this marker when they
are detected as being common, but are not included in other lists.
- gai1: common loanwords, based on the wordfreq file.
- nfxx: this is an indicator of frequency-of-use ranking in the
wordfreq file. "xx" is the number of the set of 500 words in which
the entry can be found, with "01" assigned to the first 500, "02"
to the second, and so on.
The reason both the kanji and reading elements are tagged is because
on occasions a priority is only associated with a particular
kanji/reading pair.
-->
<!-- -->
<!ELEMENT r_ele (reb, re_nokanji?, re_restr*, re_inf*, re_pri*)>
<!-- The reading element typically contains the valid readings
of the word(s) in the kanji element using modern kanadzukai.
Where there are multiple reading elements, they will typically be
alternative readings of the kanji element. In the absence of a
kanji element, i.e. in the case of a word or phrase written
entirely in kana, these elements will define the entry.
-->
<!ELEMENT reb (#PCDATA)>
<!-- this element content is restricted to kana and related
characters such as chouon and kurikaeshi. Kana usage will be
consistent between the keb and reb elements; e.g. if the keb
contains katakana, so too will the reb.
-->
<!ELEMENT re_nokanji (#PCDATA)>
<!-- This element, which will usually have a null value, indicates
that the reb, while associated with the keb, cannot be regarded
as a true reading of the kanji. It is typically used for words
such as foreign place names, gairaigo which can be in kanji or
katakana, etc.
-->
<!ELEMENT re_restr (#PCDATA)>
<!-- This element is used to indicate when the reading only applies
to a subset of the keb elements in the entry. In its absence, all
readings apply to all kanji elements. The contents of this element
must exactly match those of one of the keb elements.
-->
<!ELEMENT re_inf (#PCDATA)>
<!-- General coded information pertaining to the specific reading.
Typically it will be used to indicate some unusual aspect of
the reading. -->
<!ELEMENT re_pri (#PCDATA)>
<!-- See the comment on ke_pri above. -->
<!-- -->
<!ELEMENT info (lang*, dial*, links*, bibl*, etym*, audit*)>
<!-- general coded information relating to the entry as a whole.-->
<!ELEMENT lang (#PCDATA)>
<!-- For loan-words, the ISO 639 two-letter code for the originating
language. -->
<!ELEMENT dial (#PCDATA)>
<!-- For words specifically associated with regional dialects in
Japanese, the entity code for that dialect, e.g. ksb for Kansaiben.
-->
<!ELEMENT bibl (bib_tag?, bib_txt?)>
<!ELEMENT bib_tag (#PCDATA)>
<!ELEMENT bib_txt (#PCDATA)>
<!-- Bibliographic information about the entry. The bib_tag will a
coded reference to an entry in an external bibliographic database.
The bib_txt field may be used for brief (local) descriptions.-->
<!ELEMENT etym (#PCDATA)>
<!-- This field is used to hold information about the etymology
of the entry. -->
<!ELEMENT links (link_tag, link_desc, link_uri)>
<!ELEMENT link_tag (#PCDATA)>
<!ELEMENT link_desc (#PCDATA)>
<!ELEMENT link_uri (#PCDATA)>
<!-- This element holds details of linking information to
entries in other electronic repositories. The link_tag will be
coded to indicate the type of link (text, image, sound), the
link_desc will provided a textual label for the link, and the
link_uri contains the actual URI. -->
<!ELEMENT audit (upd_date, upd_detl)>
<!ELEMENT upd_date (#PCDATA)>
<!ELEMENT upd_detl (#PCDATA)>
<!-- The audit element will contain the date and other information
about updates to the entry. Can be used to record the source of
the material. -->
<!-- -->
<!ELEMENT sense (stagk*, stagr*, pos*, xref*, ant*, field*, misc*, s_inf*, gloss*, example*)>
<!-- The sense element will record the translational equivalent
of the Japanese word, plus other related information. Where there
are several distinctly different meanings of the word, multiple
sense elements will be employed.
-->
<!ELEMENT stagk (#PCDATA)>
<!ELEMENT stagr (#PCDATA)>
<!-- These elements, if present, indicate that the sense is restricted
to the lexeme represented by the keb and/or reb. -->
<!ELEMENT xref (#PCDATA)*>
<!-- This element is used to indicate a cross-reference to another
entry with a similar or related meaning or sense. The content of
this element must exactly match that of a keb or reb element in
another entry.
-->
<!ELEMENT ant (#PCDATA)*>
<!-- This element is used to indicate another entry which is an
antonym of the current entry/sense. The content of this element
must exactly match that of a keb or reb element in another entry.
-->
<!ELEMENT pos (#PCDATA)>
<!-- Part-of-speech information about the entry/sense. Should use
appropriate entity codes.
-->
<!ELEMENT field (#PCDATA)>
<!-- Information about the field of application of the entry. When
absent, general application is implied. Entity coding for specific
fields of application. -->
<!ELEMENT misc (#PCDATA)>
<!-- This element is used for other relevant information about
the entry. -->
<!ELEMENT gloss (#PCDATA | pri)*>
<!-- Within each sense will be one or more "glosses", i.e.
target-language words or phrases which are equivalents to the
Japanese word. This element would normally be present, however it
may be omitted in entries which are purely for a cross-reference.
-->
<!ATTLIST gloss g_lang CDATA "en">
<!-- The g_lang attribute defines the target language of the
gloss. It will be coded using the two-letter language code from
the ISO 639 standard. When absent, the value "en" (i.e. English)
is the default value. -->
<!ATTLIST gloss g_gend CDATA #IMPLIED>
<!-- The g_gend attribute defines the gender of the gloss (typically
a noun in the target language. When absent, the gender is either
not relevant or has yet to be provided.
-->
<!ELEMENT pri (#PCDATA)>
<!-- These elements highlight particular target-language words which
are strongly associated with the Japanese word. The purpose is to
establish a set of target-language words which can effectively be
used as head-words in a reverse target-language/Japanese relationship.
-->
<!ELEMENT example (#PCDATA)>
<!-- The example elements provide for pairs of short Japanese and
target-language phrases or sentences which exemplify the usage of the
Japanese head-word and the target-language gloss. Words in example
fields would typically not be indexed by a dictionary application.
-->
<!ELEMENT s_inf (#PCDATA)>
<!-- The sense-information elements provided for additional
information to be recorded about a sense. Typical usage would
be to indicate such things as level of currency of a sense, the
regional variations, etc.
-->
<!-- The following entity codes are used for common elements within the
various information fields.
-->
<!ENTITY MA "martial arts term">
<!ENTITY X "rude or X-rated term (not displayed in educational software)">
<!ENTITY abbr "abbreviation">
<!ENTITY adj "adjective (keiyoushi)">
<!ENTITY adj-na "adjectival nouns or quasi-adjectives (keiyodoshi)">
<!ENTITY adj-no "nouns which may take the genitive case particle `no'">
<!ENTITY adj-pn "pre-noun adjectival (rentaishi)">
<!ENTITY adj-t "`taru' adjective">
<!ENTITY adv "adverb (fukushi)">
<!ENTITY adv-n "adverbial noun">
<!ENTITY adv-to "adverb taking the `to' particle">
<!ENTITY arch "archaism">
<!ENTITY ateji "ateji (phonetic) reading">
<!ENTITY aux "auxiliary">
<!ENTITY aux-v "auxiliary verb">
<!ENTITY aux-adj "auxiliary adjective">
<!ENTITY Buddh "Buddhist term">
<!ENTITY chn "children's language">
<!ENTITY col "colloquialism ">
<!ENTITY comp "computer terminology">
<!ENTITY conj "conjunction">
<!ENTITY derog "derogatory">
<!ENTITY ek "exclusively kanji">
<!ENTITY exp "Expressions (phrases, clauses, etc.)">
<!ENTITY fam "familiar language ">
<!ENTITY fem "female term or language">
<!ENTITY food "food term">
<!ENTITY geom "geometry term">
<!ENTITY gikun "gikun (meaning) reading">
<!ENTITY gram "grammatical term">
<!ENTITY hon "honorific or respectful (sonkeigo) language ">
<!ENTITY hum "humble (kenjougo) language ">
<!ENTITY iK "word containing irregular kanji usage">
<!ENTITY id "idiomatic expression ">
<!ENTITY ik "word containing irregular kana usage">
<!ENTITY int "interjection (kandoushi)">
<!ENTITY io "irregular okurigana usage">
<!ENTITY iv "irregular verb">
<!ENTITY ling "linguistics terminology">
<!ENTITY m-sl "manga slang">
<!ENTITY male "male term or language">
<!ENTITY male-sl "male slang">
<!ENTITY math "mathematics">
<!ENTITY mil "military">
<!ENTITY n "noun (common) (futsuumeishi)">
<!ENTITY n-adv "adverbial noun (fukushitekimeishi)">
<!ENTITY n-suf "noun, used as a suffix">
<!ENTITY n-pref "noun, used as a prefix">
<!ENTITY n-t "noun (temporal) (jisoumeishi)">
<!ENTITY neg "negative (in a negative sentence, or with negative verb)">
<!ENTITY neg-v "negative verb (when used with)">
<!ENTITY num "numeric">
<!ENTITY oK "word containing out-dated kanji ">
<!ENTITY obs "obsolete term">
<!ENTITY obsc "obscure term">
<!ENTITY ok "out-dated or obsolete kana usage">
<!ENTITY pol "polite (teineigo) language ">
<!ENTITY pref "prefix ">
<!ENTITY prt "particle ">
<!ENTITY physics "physics terminology">
<!ENTITY qv "quod vide (see another entry)">
<!ENTITY rare "rare">
<!ENTITY sl "slang">
<!ENTITY suf "suffix ">
<!ENTITY uK "word usually written using kanji alone ">
<!ENTITY uk "word usually written using kana alone ">
<!ENTITY v1 "Ichidan verb">
<!ENTITY v5 "Godan verb (not completely classified)">
<!ENTITY v5aru "Godan verb - -aru special class">
<!ENTITY v5b "Godan verb with `bu' ending">
<!ENTITY v5g "Godan verb with `gu' ending">
<!ENTITY v5k "Godan verb with `ku' ending">
<!ENTITY v5k-s "Godan verb - Iku/Yuku special class">
<!ENTITY v5m "Godan verb with `mu' ending">
<!ENTITY v5n "Godan verb with `nu' ending">
<!ENTITY v5r "Godan verb with `ru' ending">
<!ENTITY v5r-i "Godan verb with `ru' ending (irregular verb)">
<!ENTITY v5s "Godan verb with `su' ending">
<!ENTITY v5t "Godan verb with `tsu' ending">
<!ENTITY v5u "Godan verb with `u' ending">
<!ENTITY v5u-s "Godan verb with `u' ending (special class)">
<!ENTITY v5uru "Godan verb - Uru old class verb (old form of Eru)">
<!ENTITY vi "intransitive verb ">
<!ENTITY vk "Kuru verb - special class">
<!ENTITY vs "noun or participle which takes the aux. verb suru">
<!ENTITY vs-s "suru verb - special class">
<!ENTITY vs-i "suru verb - irregular">
<!ENTITY vz "zuru verb - (alternative form of -jiru verbs)">
<!ENTITY vt "transitive verb">
<!ENTITY vulg "vulgar expression or word ">
<!ENTITY mg "masculine gender">
<!ENTITY fg "feminine gender">
<!ENTITY ng "neuter gender">
]>
<!-- JMdict created: 2006-09-11 -->
<JMdict>
<!-- JMdict Japanese-Multilingual Dictionary file (XML format) -->
<!-- Using V1.05 of the DTD -->
<!-- Copyright J.W. Breen (jwb@csse.monash.edu.au) -->
<entry>
<ent_seq>1000000</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<r_ele>
<reb>くりかえし</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>repetition mark in katakana</gloss>
<gloss g_lang="de">Wiederholungszeichen für Katakana</gloss>
<gloss g_lang="de">normalerweise nur in vertikaler Schreibweise verwendet</gloss>
<gloss g_lang="fr">marque de la répétition dans katakana</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000010</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<r_ele>
<reb>くりかえし</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>voiced repetition mark in katakana</gloss>
<gloss g_lang="de">stimmhaftes Wiederholungszeichen für Katakana</gloss>
<gloss g_lang="de">normalerweise nur in vertikaler Schreibweise verwendet</gloss>
<gloss g_lang="fr">marque de la répétition sonore dans katakana</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000020</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<r_ele>
<reb>くりかえし</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>repetition mark in hiragana</gloss>
<gloss g_lang="de">Wiederholungszeichen für Hiragana</gloss>
<gloss g_lang="de">normalerweise nur in vertikaler Schreibweise verwendet</gloss>
<gloss g_lang="fr">marque de la répétition dans hiragana</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000030</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<r_ele>
<reb>くりかえし</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>voiced repetition mark in hiragana</gloss>
<gloss g_lang="de">stimmhaftes Wiederholungszeichen für Hiragana</gloss>
<gloss g_lang="de">normalerweise nur in vertikaler Schreibweise verwendet</gloss>
<gloss g_lang="fr">marque de la répétition sonore dans hiragana</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000040</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<r_ele>
<reb>おなじく</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>ditto mark</gloss>
<gloss g_lang="ru">знак "то же самое"</gloss>
<gloss g_lang="de">Wiederholungszeichen in Tabellen</gloss>
<gloss g_lang="fr">idem marque</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000050</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<r_ele>
<reb>どうじょう</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>"as above" mark</gloss>
<gloss g_lang="de">Abkürzung für "siehe oben"</gloss>
<gloss g_lang="fr">comme au-dessus</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000060</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<r_ele>
<reb>くりかえし</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>repetition of kanji (sometimes voiced)</gloss>
<gloss g_lang="de">Wiederholungszeichen für Kanji</gloss>
<gloss g_lang="de">(Laut wird durch Wiederholung manchmal stimmhaft)</gloss>
<gloss g_lang="fr">répétition de kanji(quelquefois a exprimé)</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000070</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<r_ele>
<reb>しめ</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>end or closure mark</gloss>
<gloss g_lang="de">Zeichen als eine Art Versiegelung über der zugeklebten Lasche auf der Rückseite eines Briefumschlages</gloss>
<gloss g_lang="fr">fin ou marque de la fermeture</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000080</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<k_ele>
<keb></keb>
<ke_inf>&iK;</ke_inf>
</k_ele>
<r_ele>
<reb>かんすうじゼロ</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<xref>漢数字</xref>
<xref>ゼロ</xref>
<gloss>"kanji" zero</gloss>
<gloss g_lang="de">Kanji-Ziffer für Null</gloss>
<gloss g_lang="fr">kanji</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000090</ent_seq>
<k_ele>
<keb></keb>
</k_ele>
<k_ele>
<keb></keb>
<ke_inf>&iK;</ke_inf>
</k_ele>
<r_ele>
<reb>まる</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>circle (sometimes used for zero)</gloss>
<gloss g_lang="ru">круг</gloss>
<gloss g_lang="ru">но́ль</gloss>
<gloss g_lang="de">Kreis</gloss>
<gloss g_lang="de">Markierung für "richtig"</gloss>
<gloss g_lang="de">Maru</gloss>
<gloss g_lang="de">(ein japan. Schriftfont hat mindestens drei verschiedene Codierungen und Darstellungen für "maru")</gloss>
<gloss g_lang="fr">entourez</gloss>
<gloss g_lang="fr">mettez à zéro</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000100</ent_seq>
<k_ele>
<keb>ABC順</keb>
</k_ele>
<r_ele>
<reb>エービーシーじゅん</reb>
</r_ele>
<r_ele>
<reb>ええびいしいじゅん</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>alphabetical order</gloss>
<gloss g_lang="de">alphabetische Ordnung</gloss>
<gloss g_lang="de">alphabetische Reihenfolge</gloss>
<gloss g_lang="fr">ordre alphabétique</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000110</ent_seq>
<k_ele>
<keb>CDプレーヤー</keb>
</k_ele>
<r_ele>
<reb>シーディープレーヤー</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>CD player</gloss>
<gloss g_lang="ru">CD плеер</gloss>
<gloss g_lang="ru">проигрыватель компакт-дисков</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000120</ent_seq>
<k_ele>
<keb>Hな映画</keb>
</k_ele>
<k_ele>
<keb>エッチな映画</keb>
</k_ele>
<r_ele>
<reb>エッチなえいが</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>pornographic film</gloss>
<gloss>salacious film</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000130</ent_seq>
<k_ele>
<keb>N響</keb>
</k_ele>
<r_ele>
<reb>エヌきょう</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<misc>&abbr;</misc>
<gloss>NHK Symphony Orchestra</gloss>
<gloss g_lang="fr">NHK Symphonie Orchestre(abbr)</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000140</ent_seq>
<r_ele>
<reb>Oバック</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>O-back</gloss>
<gloss>skirt with peek-a-boo hole in rump</gloss>
<gloss g_lang="fr">O En arrière</gloss>
<gloss g_lang="fr">contournez avec coucou trou dans croupe</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
<entry>
<ent_seq>1000150</ent_seq>
<r_ele>
<reb>RS232ケーブル</reb>
</r_ele>
<sense>
<pos>&n;</pos>
<gloss>rs232 cable</gloss>
<gloss g_lang="fr">les rs232 câblent</gloss>
<gloss g_lang="fr">(JF2)</gloss>
</sense>
</entry>
</JMdict>

Просмотреть файл

@ -1,678 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css"
href="../../documentation/documentation.css"
?>
<?xml-stylesheet type="text/xsl"
href="../../documentation/documentation.xsl"
?>
<!DOCTYPE documentation SYSTEM "http://www.germane-software.com/software/documentation/documentation.dtd">
<documentation>
<head>
<title>REXML Tutorial</title>
<version>$Revision: 1.1.2.1 $</version>
<date>*2001-296+594</date>
<home>http://www.germane-software.com/~ser/software/rexml</home>
<base></base>
<language>ruby</language>
<author email="ser@germane-software.com"
href="http://www.germane-software.com/~ser">Sean Russell</author>
</head>
<overview>
<purpose lang="en">
<p>This is a tutorial for using <link
href="http://www.germane-software.com/~ser/software/rexml">REXML</link>,
a pure Ruby XML processor.</p>
</purpose>
<general>
<p>REXML was inspired by the Electric XML library for Java, which
features an easy-to-use API, small size, and speed. Hopefully, REXML,
designed with the same philosophy, has these same features. I've tried
to keep the API as intuitive as possible, and have followed the Ruby
methodology for method naming and code flow, rather than mirroring the
Java API.</p>
<p>REXML supports both tree and stream document parsing. Stream parsing
is faster (about 1.5 times as fast). However, with stream parsing, you
don't get access to features such as XPath.</p>
<p>The <link href="../doc/index.html">API</link> documentation also
contains code snippits to help you learn how to use various methods.
This tutorial serves as a starting point and quick guide to using
REXML.</p>
<subsection title="Tree Parsing XML and accessing Elements">
<p>We'll start with parsing an XML document</p>
<example>require "rexml/document"
file = File.new( "mydoc.xml" )
doc = REXML::Document.new file</example>
<p>Line 3 creates a new document and parses the supplied file. You can
also do the following</p>
<example>require "rexml/document"
include REXML # so that we don't have to prefix everything with REXML::...
string = &lt;&lt;EOF
&lt;mydoc&gt;
&lt;someelement attribute="nanoo"&gt;Text, text, text&lt;/someelement&gt;
&lt;/mydoc&gt;
EOF
doc = Document.new string</example>
<p>So parsing a string is just as easy as parsing a file. For future
examples, I'm going to omit both the <code>require</code> and
<code>include</code> lines.</p>
<p>Once you have a document, you can access elements in that document
in a number of ways:</p>
<list>
<item>The <code>Element</code> class itself has
<code>each_element_with_attribute</code>, a common way of accessing
elements.</item>
<item>The attribute <code>Element.elements</code> is an
<code>Elements</code> class instance which has the <code>each</code>
and <code>[]</code> methods for accessing elements. Both methods can
be supplied with an XPath for filtering, which makes them very
powerful.</item>
<item>Since <code>Element</code> is a subclass of Parent, you can
also access the element's children directly through the Array-like
methods <code>Element[], Element.each, Element.find,
Element.delete</code>. This is the fastest way of accessing
children, but note that, being a true array, XPath searches are not
supported, and that all of the element children are contained in
this array, not just the Element children.</item>
</list>
<p>Here are a few examples using these methods. First is the source
document used in the examples. Save this as mydoc.xml before running
any of the examples that require it:</p>
<example title="The source document">&lt;inventory title="OmniCorp Store #45x10^3"&gt;
&lt;section name="health"&gt;
&lt;item upc="123456789" stock="12"&gt;
&lt;name&gt;Invisibility Cream&lt;/name&gt;
&lt;price&gt;14.50&lt;/price&gt;
&lt;description&gt;Makes you invisible&lt;/description&gt;
&lt;/item&gt;
&lt;item upc="445322344" stock="18"&gt;
&lt;name&gt;Levitation Salve&lt;/name&gt;
&lt;price&gt;23.99&lt;/price&gt;
&lt;description&gt;Levitate yourself for up to 3 hours per application&lt;/description&gt;
&lt;/item&gt;
&lt;/section&gt;
&lt;section name="food"&gt;
&lt;item upc="485672034" stock="653"&gt;
&lt;name&gt;Blork and Freen Instameal&lt;/name&gt;
&lt;price&gt;4.95&lt;/price&gt;
&lt;description&gt;A tasty meal in a tablet; just add water&lt;/description&gt;
&lt;/item&gt;
&lt;item upc="132957764" stock="44"&gt;
&lt;name&gt;Grob winglets&lt;/name&gt;
&lt;price&gt;3.56&lt;/price&gt;
&lt;description&gt;Tender winglets of Grob. Just add water&lt;/description&gt;
&lt;/item&gt;
&lt;/section&gt;
&lt;/inventory&gt;</example>
<example title="Accessing Elements">doc = Document.new File.new("mydoc.xml")
doc.elements.each("inventory/section") { |element| puts element.attributes["name"] }
# -&gt; health
# -&gt; food
doc.elements.each("*/section/item") { |element| puts element.attributes["upc"] }
# -&gt; 123456789
# -&gt; 445322344
# -&gt; 485672034
# -&gt; 132957764
root = doc.root
puts root.attributes["title"]
# -&gt; OmniCorp Store #45x10^3
puts root.elements["section/item[@stock='44']"].attributes["upc"]
# -&gt; 132957764
puts root.elements["section"].attributes["name"]
# -&gt; health (returns the first encountered matching element)
puts root.elements[1].attributes["name"]
# -&gt; health (returns the FIRST child element)
root.detect {|node| node.kind_of? Element and node.attributes["name"] == "food" }</example>
<p>Notice the second-to-last line of code. Element children in REXML
are indexed starting at 1, not 0. This is because XPath itself counts
elements from 1, and REXML maintains this relationship; IE,
<code>root.elements['*[1]'] == root.elements[1]</code>. The last line
finds the first child element with the name of "food". As you can see
in this example, accessing attributes is also straightforward.</p>
<p>You can also access xpaths directly via the XPath class.</p>
<example title="Using XPath"># The invisibility cream is the first &lt;item&gt;
invisibility = XPath.first( doc, "//item" )
# Prints out all of the prices
XPath.each( doc, "//price") { |element| puts element.text }
# Gets an array of all of the "name" elements in the document.
names = XPath.match( doc, "//name" ) </example>
<p>Another way of getting an array of matching nodes is through
Element.elements.to_a(). Although this is a method on elements, if
passed an XPath it can return an array of arbitrary objects. This is
due to the fact that XPath itself can return arbitrary nodes
(Attribute nodes, Text nodes, and Element nodes).</p>
<example title="Using to_a()">all_elements = doc.elements.to_a
all_children = doc.to_a
all_upc_strings = doc.elements.to_a( "//item/attribute::upc" )
all_name_elements = doc.elements.to_a( "//name" )</example>
</subsection>
<subsection title="Text Nodes">
<p>REXML attempts to make the common case simple, but this means that
the uncommon case can be complicated. This is especially true with
Text nodes.</p>
<p>Text nodes have a lot of behavior, and in the case of internal
entities, what you get may be different from what you expect. When
REXML reads an XML document, in parses the DTD and creates an internal
table of entities. If it finds any of these entities in the document,
it replaces them with their values:</p>
<example title="Entity Replacement">doc = Document.new '&lt;!DOCTYPE foo [
&lt;!ENTITY ent "replace"&gt;
]&gt;&lt;a&gt;&amp;ent;&lt;/a&gt;'
doc.root.text #-&gt; "replace"
</example>
<p>When you write the document back out, REXML replaces the values
with the entity reference:</p>
<example>doc.to_s
# Generates:
# &lt;!DOCTYPE foo [
# &lt;!ENTITY ent "replace"&gt;
# ]&gt;&lt;a&gt;&amp;ent;&lt;/a&gt;</example>
<p>But there's a problem. What happens if only some of the words are
also entity reference values?</p>
<example>doc = Document.new '&lt;!DOCTYPE foo [
&lt;!ENTITY ent "replace"&gt;
]&gt;&lt;a&gt;replace &amp;ent;&lt;/a&gt;'
doc.root.text #-&gt; "replace replace"
</example>
<p>Well, REXML does the only thing it can:</p>
<example>doc.to_s
# Generates:
# &lt;!DOCTYPE foo [
# &lt;!ENTITY ent "replace"&gt;
# ]&gt;&lt;a&gt;&amp;ent; &amp;ent;&lt;/a&gt;</example>
<p>This is probably not what you expect. However, when designing
REXML, I had a choice between this behavior, and using immutable text
nodes. The problem is that, if you can change the text in a node,
REXML can never tell which tokens you want to have replaced with
entities. There is a wrinkle: REXML will write what it gets in as long
as you don't access the text. This is because REXML does lazy
evaluation of entities. Therefore,</p>
<example title="Lazy Evaluation">doc = Document.new( '&lt;!DOCTYPE foo
[ &lt;!ENTITY ent "replace"&gt; ]&gt;&lt;a&gt;replace
&amp;ent;&lt;/a&gt;' ) doc.to_s # Generates: # &lt;!DOCTYPE foo [ #
&lt;!ENTITY ent "replace"&gt; # ]&gt;&lt;a&gt;<emphasis>replace
&amp;ent;</emphasis>&lt;/a&gt; doc.root.text #-&gt; Now accessed,
entities have been resolved doc.to_s # Generates: # &lt;!DOCTYPE foo [
# &lt;!ENTITY ent "replace"&gt; # ]&gt;&lt;a&gt;<emphasis>&amp;ent;
&amp;ent;</emphasis>&lt;/a&gt;</example>
<p>There is a programmatic solution: <code>:raw</code>. If you set the
<code>:raw</code> flag on any Text or Element node, the entities
within that node will not be processed. This means that you'll have to
deal with entities yourself:</p>
<example title="Entity Replacement">doc = Document.new('&lt;!DOCTYPE
foo [ &lt;!ENTITY ent "replace"&gt; ]&gt;&lt;a&gt;replace
&amp;ent;&lt;/a&gt;',<emphasis>{:raw=&gt;:all})</emphasis>
doc.root.text #-&gt; "replace &amp;ent;" doc.to_s # Generates: #
&lt;!DOCTYPE foo [ # &lt;!ENTITY ent "replace"&gt; #
]&gt;&lt;a&gt;replace &amp;ent;&lt;/a&gt;</example>
</subsection>
<subsection title="Creating XML documents">
<p>Again, there are a couple of mechanisms for creating XML documents
in REXML. Adding elements by hand is faster than the convenience
method, but which you use will probably be a matter of aesthetics.</p>
<example title="Creating elements">el = someelement.add_element "myel"
# creates an element named "myel", adds it to "someelement", and returns it
el2 = el.add_element "another", {"id"=&gt;"10"}
# does the same, but also sets attribute "id" of el2 to "10"
el3 = Element.new "blah"
el1.elements &lt;&lt; el3
el3.attributes["myid"] = "sean"
# creates el3 "blah", adds it to el1, then sets attribute "myid" to "sean"</example>
<p>If you want to add text to an element, you can do it by either
creating Text objects and adding them to the element, or by using the
convenience method <code>text=</code></p>
<example title="Adding text">el1 = Element.new "myelement"
el1.text = "Hello world!"
# -&gt; &lt;myelement&gt;Hello world!&lt;/myelement&gt;
el1.add_text "Hello dolly"
# -&gt; &lt;myelement&gt;Hello world!Hello dolly&lt;/element&gt;
el1.add Text.new("Goodbye")
# -&gt; &lt;myelement&gt;Hello world!Hello dollyGoodbye&lt;/element&gt;
el1 &lt;&lt; Text.new(" cruel world")
# -&gt; &lt;myelement&gt;Hello world!Hello dollyGoodbye cruel world&lt;/element&gt;</example>
<p>But note that each of these text objects are still stored as
separate objects; <code>el1.text</code> will return "Hello world!";
<code>el1[2]</code> will return a Text object with the contents
"Goodbye".</p>
<p>Please be aware that all text nodes in REXML are UTF-8 encoded, and
all of your code must reflect this. You may input and output other
encodings (UTF-8, UTF-16, ISO-8859-1, and UNILE are all supported,
input and output), but within your program, you must pass REXML UTF-8
strings.</p>
<p>I can't emphasize this enough, because people do have problems with
this. REXML can't possibly alway guess correctly how your text is
encoded, so it always assumes the text is UTF-8. It also does not warn
you when you try to add text which isn't properly encoded, for the
same reason. You must make sure that you are adding UTF-8 text.
&#160;If you're adding standard 7-bit ASCII, which is most common, you
don't have to worry. &#160;If you're using ISO-8859-1 text (characters
above 0x80), you must convert it to UTF-8 before adding it to an
element. &#160;You can do this with the shard:
<code>text.unpack("C*").pack("U*")</code>. If you ignore this warning
and add 8-bit ASCII characters to your documents, your code may
work... or it may not. &#160;In either case, REXML is not at fault.
You have been warned.</p>
<p>One last thing: alternate encoding output support only works from
Document.write() and Document.to_s(). If you want to write out other
nodes with a particular encoding, you must wrap your output object
with Output:</p>
<example title="Encoded Output">e = Element.new "&lt;a/&gt;"
e.text = "f\xfcr" # ISO-8859-1 'ü'
o = ''
e.write( Output.new( o, "ISO-8859-1" ) )
</example>
<p>You can pass Output any of the supported encodings.</p>
<p>If you want to insert an element between two elements, you can use
either the standard Ruby array notation, or
<code>Parent.insert_before</code> and
<code>Parent.insert_after</code>.</p>
<example title="Inserts">doc = Document.new "&lt;a&gt;&lt;one/&gt;&lt;three/&gt;&lt;/a&gt;"
doc.root[1,0] = Element.new "two"
# -&gt; &lt;a&gt;&lt;one/&gt;&lt;two/&gt;&lt;three/&gt;&lt;/a&gt;
three = doc.elements["a/three"]
doc.root.insert_after three, Element.new "four"
# -&gt; &lt;a&gt;&lt;one/&gt;&lt;two/&gt;&lt;three/&gt;&lt;four/&gt;&lt;/a&gt;
# A convenience method allows you to insert before/after an XPath:
doc.root.insert_after( "//one", Element.new("one-five") )
# -&gt; &lt;a&gt;&lt;one/&gt;&lt;one-five/&gt;&lt;two/&gt;&lt;three/&gt;&lt;four/&gt;&lt;/a&gt;
# Another convenience method allows you to insert after/before an element:
four = doc.elements["//four"]
four.previous_sibling = Element.new("three-five")
# -&gt; &lt;a&gt;&lt;one/&gt;&lt;one-five/&gt;&lt;two/&gt;&lt;three/&gt;&lt;three-five/&gt;&lt;four/&gt;&lt;/a&gt;</example>
<p>The <code>raw</code> flag in the <code>Text</code> constructor can
be used to tell REXML to leave strings which have entities defined for
them alone.</p>
<example title="Raw text">doc = Document.new( "&lt;?xml version='1.0?&gt;
&lt;!DOCTYPE foo SYSTEM 'foo.dtd' [
&lt;!ENTITY % s "Sean"&gt;
]&gt;
&lt;a/&gt;"
t = Text.new( "Sean", false, nil, false )
doc.root.text = t
t.to_s # -&gt; &amp;s;
t = Text.new( "Sean", false, nil, true )
doc.root.text = t
t.to_s # -&gt; Sean</example>
<p>Note that, in all cases, the <code>value()</code> method returns
the text with entities expanded, so the <code>raw</code> flag only
affects the <code>to_s()</code> method. If the <code>raw</code> is set
for a text node, then <code>to_s()</code> will not entities will not
normalize (turn into entities) entity values. You can not create raw
text nodes that contain illegal XML, so the following will generate a
parse error:</p>
<example>t = Text.new( "&amp;", false, nil, true )</example>
<p>You can also tell REXML to set the Text children of given elements
to raw automatically, on parsing or creating:</p>
<example title="Automatic raw text handling">doc = REXML::Document.new( source, { :raw =&gt; %w{ tag1 tag2 tag3 } }</example>
<p>In this example, all tags named "tag1", "tag2", or "tag3" will have
any Text children set to raw text. If you want to have all of the text
processed as raw text, pass in the :all tag:</p>
<example title="Raw documents">doc = REXML::Document.new( source, { :raw =&gt; :all })</example>
</subsection>
<subsection title="Writing a tree">
<p>There aren't many things that are more simple than writing a REXML
tree. Simply pass an object that supports <code>&lt;&lt;( String
)</code> to the <code>write</code> method of any object. In Ruby, both
IO instances (File) and String instances support &lt;&lt;.</p>
<example>doc.write $stdout
output = ""
doc.write output</example>
<p>If you want REXML to pretty-print output, pass <code>write()</code>
an indent value greater than -1:</p>
<example title="Write with pretty-printing">doc.write( $stdout, 0 )</example>
<p>REXML will not, by default, write out the XML declaration unless
you specifically ask for them. If a document is read that contains an
XML declaration, that declaration <emphasis>will</emphasis> be written
faithfully. The other way you can tell REXML to write the declaration
is to specifically add the declaration:</p>
<example title="Adding an XML Declaration to a Document">doc = Document.new
doc.add_element 'foo'
doc.to_s #-&gt; &lt;foo/&gt;
doc &lt;&lt; XMLDecl.new
doc.to_s #-&gt; &lt;?xml version='1.0'?&gt;&lt;foo/&gt;</example>
</subsection>
<subsection title="Iterating">
<p>There are four main methods of iterating over children.
<code>Element.each</code>, which iterates over all the children;
<code>Element.elements.each</code>, which iterates over just the child
Elements; <code>Element.next_element</code> and
<code>Element.previous_element</code>, which can be used to fetch the
next Element siblings; and <code>Element.next_sibling</code> and
<code>Eleemnt.previous_sibling</code>, which fetches the next and
previous siblings, regardless of type.</p>
</subsection>
<subsection title="Stream Parsing">
<p>REXML stream parsing requires you to supply a Listener class. When
REXML encounters events in a document (tag start, text, etc.) it
notifies your listener class of the event. You can supply any subset
of the methods, but make sure you implement method_missing if you
don't implement them all. A StreamListener module has been supplied as
a template for you to use.</p>
<example title="Stream parsing">list = MyListener.new
source = File.new "mydoc.xml"
REXML::Document.parse_stream(source, list)</example>
<p>Stream parsing in REXML is much like SAX, where events are
generated when the parser encounters them in the process of parsing
the document. When a tag is encountered, the stream listener's
<code>tag_start()</code> method is called. When the tag end is
encountered, <code>tag_end()</code> is called. When text is
encountered, <code>text()</code> is called, and so on, until the end
of the stream is reached. One other note: the method
<code>entity()</code> is called when an <code>&amp;entity;</code> is
encountered in text, and only then.</p>
<p>Please look at the <link
href="../doc/classes/REXML/StreamListener.html">StreamListener
API</link> for more information.<footnote>You must generate the API
documentation with rdoc or download the API documentation from the
REXML website for this documentation.</footnote></p>
</subsection>
<subsection title="Whitespace">
<p>By default, REXML respects whitespace in your document. In many
applications, you want the parser to compress whitespace in your
document. In these cases, you have to tell the parser which elements
you want to respect whitespace in by passing a context to the
parser:</p>
<example title="Compressing whitespace">doc = REXML::Document.new( source, { :compress_whitespace =&gt; %w{ tag1 tag2 tag3 } }</example>
<p>Whitespace for tags "tag1", "tag2", and "tag3" will be compressed;
all other tags will have their whitespace respected. Like :raw, you
can set :compress_whitespace to :all, and have all elements have their
whitespace compressed.</p>
<p>You may also use the tag <code>:respect_whitespace</code>, which
flip-flops the behavior. If you use <code>:respect_whitespace</code>
for one or more tags, only those elements will have their whitespace
respected; all other tags will have their whitespace compressed.</p>
</subsection>
<subsection title="Automatic Entity Processing">
<p>REXML does some automatic processing of entities for your
convenience. The processed entities are &amp;, &lt;, &gt;, ", and '.
If REXML finds any of these characters in Text or Attribute values, it
automatically turns them into entity references when it writes them
out. Additionally, when REXML finds any of these entity references in
a document source, it converts them to their character equivalents.
All other entity references are left unprocessed. If REXML finds an
&amp;, &lt;, or &gt; in the document source, it will generate a
parsing error.</p>
<example title="Entity processing">bad_source = "&lt;a&gt;Cats &amp; dogs&lt;/a&gt;"
good_source = "&lt;a&gt;Cats &amp;amp; &amp;#100;ogs&lt;/a&gt;"
doc = REXML::Document.new bad_source
# Generates a parse error
doc = REXML::Document.new good_source
puts doc.root.text
# -&gt; "Cats &amp; &amp;#100;ogs"
doc.root.write $stdout
# -&gt; "&lt;a&gt;Cats &amp;amp; &amp;#100;ogs&lt;/a&gt;"
doc.root.attributes["m"] = "x'y\"z"
puts doc.root.attributes["m"]
# -&gt; "x'y\"z"
doc.root.write $stdout
# -&gt; "&lt;a m='x&amp;apos;y&amp;quot;z'&gt;Cats &amp;amp; &amp;#100;ogs&lt;/a&gt;"</example>
</subsection>
<subsection title="Namespaces">
<p>Namespaces are fully supported in REXML and within the XPath
parser. There are a few caveats when using XPath, however:</p>
<list>
<item>If you don't supply a namespace mapping, the default namespace
mapping of the context element is used. This has its limitations,
but is convenient for most purposes.</item>
<item>If you need to supply a namespace mapping, you must use the
XPath methods <code>each</code>, <code>first</code>, and
<code>match</code> and pass them the mapping.</item>
</list>
<example title="Using namespaces">source = "&lt;a xmlns:x='foo' xmlns:y='bar'&gt;&lt;x:b id='1'/&gt;&lt;y:b id='2'/&gt;&lt;/a&gt;"
doc = Document.new source
doc.elements["/a/x:b"].attributes["id"] # -&gt; '1'
XPath.first(doc, "/a/m:b", {"m"=&gt;"bar"}).attributes["id"] # -&gt; '2'
doc.elements["//x:b"].prefix # -&gt; 'x'
doc.elements["//x:b"].namespace # -&gt; 'foo'
XPath.first(doc, "//m:b", {"m"=&gt;"bar"}).prefix # -&gt; 'y'</example>
</subsection>
<subsection title="Pull parsing">
<p>The pull parser API is not yet stable. When it settles down, I'll
fill in this section. For now, you'll have to bite the bullet and read
the <link
href="http://www.germane-software.com/software/rexml_doc/classes/REXML/PullParser.html">PullParser</link>
API docs. Ignore the PullListener class; it is a private helper
class.</p>
</subsection>
<subsection title="SAX2 Stream Parsing">
<p>The original REXML stream parsing API is very minimal. This also
means that it is fairly fast. For a more complex, more "standard" API,
REXML also includes a streaming parser with a SAX2+ API. This API
differs from SAX2 in a couple of ways, such as having more filters and
multiple notification mechanisms, but the core API is SAX2.</p>
<p>The two classes in the SAX2 API are <link
href="http://www.germane-software.com/software/rexml_doc/classes/REXML/SAX2Parser.html"><code>SAX2Parser</code></link>
and <link
href="http://www.germane-software.com/software/rexml_doc/classes/REXML/SAX2Listener.html"><code>SAX2Listener</code></link>.
You can use the parser in one of five ways, depending on your needs.
Three of the ways are useful if you are filtering for a small number
of events in the document, such as just printing out the names of all
of the elements in a document, or getting all of the text in a
document. The other two ways are for more complex processing, where
you want to be notified of multiple events. The first three involve
Procs, and the last two involve listeners. The listener mechanisms are
very similar to the original REXML streaming API, with the addition of
filtering options, and are faster than the proc mechanisms.</p>
<p>An example is worth a thousand words, so we'll just take a look at
a small example of each of the mechanisms. The first example involves
printing out only the text content of a document.</p>
<example title="Filtering for Events with Procs">require 'rexml/sax2parser'
parser = REXML::SAX2Parser.new( File.new( 'documentation.xml' ) )
parser.listen( :characters ) {|text| puts text }
parser.parse</example>
<p>In this example, we tell the parser to call our block for every
<code>characters</code> event. "characters" is what SAX2 calls Text
nodes. The event is identified by the symbol <code>:characters</code>.
There are a number of these events, including
<code>:element_start</code>, <code>:end_prefix_mapping</code>, and so
on; the events are named after the methods in the
<code>SAX2Listener</code> API, so refer to that document for a
complete list.</p>
<p>You can additionally filter for particular elements by passing an
array of tag names to the <code>listen</code> method. In further
examples, we will not include the <code>require</code> or parser
construction lines, as they are the same for all of these
examples.</p>
<example title="Filtering for Events on Particular Elements with Procs">parser.listen( :characters, %w{ changelog todo } ) {|text| puts text }
parser.parse</example>
<p>In this example, only the text content of changelog and todo
elements will be printed. The array of tag names can also contain
regular expressions which the element names will be matched
against.</p>
<p>Finally, as a shortcut, if you do not pass a symbol to the listen
method, it will default to <code>:element_start</code></p>
<example title="Default Events">parser.listen( %w{ item }) do |uri,localname,qname,attributes|
puts attributes['version']
end
parser.parse</example>
<p>This example prints the "version" attribute of all "item" elements
in the document. Notice that the number of arguments passed to the
block is larger than for <code>:text</code>; again, check the
SAX2Listener API for a list of what arguments are passed the blocks
for a given event.</p>
<p>The last two mechanisms for parsing use the SAX2Listener API. Like
StreamListener, SAX2Listener is a <code>module</code>, so you can
<code>include</code> it in your class to give you an adapter. To use
the listener model, create a class that implements some of the
SAX2Listener methods, or all of them if you don't include the
SAX2Listener model. Add them to a parser as you would blocks, and when
the parser is run, the methods will be called when events occur.
Listeners do not use event symbols, but they can filter on element
names.</p>
<example title="Filtering for Events with Listeners">listener1 = MySAX2Listener.new
listener2 = MySAX2Listener.new
parser.listen( listener1 )
parser.listen( %{ changelog, todo, credits }, listener2 )
parser.parse</example>
<p>In the previous example, <code>listener1</code> will be notified of
all events that occur, and <code>listener2</code> will only be
notified of events that occur in <code>changelog</code>,
<code>todo</code>, and <code>credits</code> elements. We also see that
multiple listeners can be added to the same parser; multiple blocks
can also be added, and listeners and blocks can be mixed together.</p>
<p>There is, as yet, no mechanism for recursion. Two upcoming features
of the SAX2 API will be the ability to filter based on an XPath, and
the ability to specify filtering on an elemnt and all of its
descendants.</p>
<p><em>WARNING:</em> The SAX2 API for dealing with doctype (DTD)
events almost <em>certainly</em> will change.</p>
</subsection>
<subsection title="Convenience methods">
<p>Michael Neumann contributed some convenience functions for nodes,
and they are general enough that I've included. Michael's use-case
examples follow: <example title="Node convenience functions">#
Starting with +root_node+, we recursively look for a node with the
given # +tag+, the given +attributes+ (a Hash) and whoose text equals
or matches the # +text+ string or regular expression. # # To find the
following node: # # &lt;td class='abc'&gt;text&lt;/td&gt; # # We use:
# # find_node(root, 'td', {'class' =&gt; 'abc'}, "text") # # Returns
+nil+ if no matching node was found. def find_node(root_node, tag,
attributes, text) root_node.find_first_recursive {|node| node.name ==
tag and attributes.all? {|attr, val| node.attributes[attr] == val} and
text === node.text } end # # Extract specific columns (specified by
the position of it's corresponding # header column) from a table. # #
Given the following table: # # &lt;table&gt; # &lt;tr&gt; #
&lt;td&gt;A&lt;/td&gt; # &lt;td&gt;B&lt;/td&gt; #
&lt;td&gt;C&lt;/td&gt; # &lt;/tr&gt; # &lt;tr&gt; #
&lt;td&gt;A.1&lt;/td&gt; # &lt;td&gt;B.1&lt;/td&gt; #
&lt;td&gt;C.1&lt;/td&gt; # &lt;/tr&gt; # &lt;tr&gt; #
&lt;td&gt;A.2&lt;/td&gt; # &lt;td&gt;B.2&lt;/td&gt; #
&lt;td&gt;C.2&lt;/td&gt; # &lt;/tr&gt; # &lt;/table&gt; # # To extract
the first (A) and last (C) column: # # extract_from_table(root_node,
["A", "C"]) # # And you get this as result: # # [ # ["A.1", "C.1"], #
["A.2", "C.2"] # ] # def extract_from_table(root_node, headers) #
extract and collect all header nodes header_nodes = headers.collect {
|header| find_node(root_node, 'td', {}, header) } raise "some headers
not found" if header_nodes.compact.size &lt; headers.size # assert
that all headers have the same parent 'header_row', which is the row #
in which the header_nodes are contained. 'table' is the surrounding
table tag. header_row = header_nodes.first.parent table =
header_row.parent raise "different parents" unless header_nodes.all?
{|n| n.parent == header_row} # we now iterate over all rows in the
table that follows the header_row. # for each row we collect the
elements at the same positions as the header_nodes. # this is what we
finally return from the method. (header_row.index_in_parent+1 ..
table.elements.size).collect do |inx| row = table.elements[inx]
header_nodes.collect { |n| row.elements[ n.index_in_parent ].text }
end end</example></p>
</subsection>
<subsection title="Conclusion">
<p>This isn't everything there is to REXML, but it should be enough to
get started. Check the <link href="../doc/index.html">API
documentation</link><footnote>You must generate the API documentation
with rdoc or download the API documentation from the REXML website for
this documentation.</footnote> for particulars and more examples.
There are plenty of unit tests in the <code>test/</code> directory,
and these are great sources of working examples.</p>
</subsection>
</general>
</overview>
<credits>
<p>Among the people who've contributed to this document are:</p>
<list>
<item><link href="mailto:deicher@sandia.gov">Eichert, Diana</link> (bug
fix)</item>
</list>
</credits>
</documentation>

Просмотреть файл

@ -1,6 +0,0 @@
<?xml version="1.0" ?>
<root a="1" _a="2">
<b>1</b>
<_b>2</_b>
</root>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше