mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
0f18bc7fca
NOTE: It's a backward incompatible change. If we have any serious problems with this change, we may revert this change. The XML namespace specification says the default namespace doesn't apply to attribute names but it does in REXML without this change: https://www.w3.org/TR/xml-names/#uniqAttrs > the default namespace does not apply to attribute names REXML reports a parse error for the following XML that is described as a valid XML in the XML nsmaspace specification without this change: <!-- http://www.w3.org is bound to n1 and is the default --> <x xmlns:n1="http://www.w3.org" xmlns="http://www.w3.org" > <good a="1" b="2" /> <good a="1" n1:a="2" /> </x> If attribute doesn't have prefix, the attribute should return "" for both #prefix and #namespace. https://github.com/ruby/rexml/commit/9e4fd552bc
1517 lines
45 KiB
Ruby
1517 lines
45 KiB
Ruby
# -*- coding: utf-8 -*-
|
|
# frozen_string_literal: false
|
|
|
|
require_relative "rexml_test_utils"
|
|
|
|
require "rexml/document"
|
|
require "rexml/parseexception"
|
|
require "rexml/output"
|
|
require "rexml/source"
|
|
require "rexml/formatters/pretty"
|
|
require "rexml/undefinednamespaceexception"
|
|
|
|
require_relative "listener"
|
|
|
|
module REXMLTests
|
|
class Tester < Test::Unit::TestCase
|
|
include REXMLTestUtils
|
|
include REXML
|
|
def setup
|
|
@xsa_source = <<-EOL
|
|
<?xml version="1.0"?>
|
|
<?xsl stylesheet="blah.xsl"?>
|
|
<!-- The first line tests the XMLDecl, the second tests PI.
|
|
The next line tests DocType. This line tests comments. -->
|
|
<!DOCTYPE xsa PUBLIC
|
|
"-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML"
|
|
"http://www.garshol.priv.no/download/xsa/xsa.dtd">
|
|
|
|
<xsa>
|
|
<vendor id="blah">
|
|
<name>Lars Marius Garshol</name>
|
|
<email>larsga@garshol.priv.no</email>
|
|
<url>http://www.stud.ifi.uio.no/~lmariusg/</url>
|
|
</vendor>
|
|
</xsa>
|
|
EOL
|
|
end
|
|
|
|
def test_bad_markup
|
|
[
|
|
"<pkg='version'> foo </pkg>",
|
|
'<0/>',
|
|
'<a>&</a>',
|
|
'<a>&a</a>',
|
|
# '<a>&a;</a>', # FIXME
|
|
'<a a="<"/>',
|
|
'<a 3="<"/>',
|
|
'<a a="1" a="2"/>',
|
|
'<a><!-- -- --></a>',
|
|
'<a><!-- ---></a>',
|
|
'<a>�</a>',
|
|
'<a>�</a>',
|
|
"<a a='�' />",
|
|
"<a>\f</a>",
|
|
"<a a='\f' />",
|
|
"<a>\000</a>",
|
|
# FIXME '<a' + [65535].pack('U') + ' />',
|
|
'<a></a>',
|
|
'<a></a>',
|
|
# FIXME '<a' + [0x0371].pack('U') + ' />',
|
|
# FIXME '<a a' + [0x0371].pack('U') + '="" />',
|
|
].each do |src|
|
|
assert_raise( ParseException, %Q{Parse #{src.inspect} should have failed!} ) do
|
|
Document.new(src)
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_attribute
|
|
# Testing constructors
|
|
#a = Attribute.new "hello", "dolly"
|
|
#b = Attribute.new a
|
|
#d = Document.new( "<a hello='dolly' href='blah'/>" )
|
|
#c = d[0].attributes.get_attribute( "hello" )
|
|
|
|
#assert_equal a, b
|
|
#for attr in [ a, b, c]
|
|
# assert_equal "hello", attr.name
|
|
# assert_equal "dolly", attr.value
|
|
#end
|
|
|
|
# This because of a reported bug in attribute handling in 1.0a8
|
|
source = '<a att="A">blah</a>'
|
|
doc = Document.new source
|
|
doc.elements.each do |a|
|
|
a.attributes['att'] << 'B'
|
|
assert_equal "AB", a.attributes['att']
|
|
a.attributes['att'] = 'C'
|
|
assert_equal "C", a.attributes['att']
|
|
end
|
|
|
|
# Bryan Murphy <murphybryanp@yahoo.com>
|
|
text = "this is a {target[@name='test']/@value} test"
|
|
source = <<-EOL
|
|
<?xml version="1.0"?>
|
|
<doc search="#{text}"/>
|
|
EOL
|
|
|
|
xml = Document.new source
|
|
value = xml.root.attributes["search"]
|
|
assert_equal text, value.to_s
|
|
|
|
e = Element.new "test"
|
|
e.add_attributes({ "name1" => "test1", "name4" => "test4" })
|
|
e.add_attributes([["name3","test3"], ["name2","test2"]])
|
|
assert_equal "test1", e.attributes["name1"]
|
|
assert_equal "test2", e.attributes["name2"]
|
|
assert_equal "test3", e.attributes["name3"]
|
|
assert_equal "test4", e.attributes["name4"]
|
|
|
|
# ensure that the attributes come out in sorted order
|
|
assert_equal %w(<test
|
|
name1='test1'
|
|
name2='test2'
|
|
name3='test3'
|
|
name4='test4'/>).join(' '), e.to_s
|
|
end
|
|
|
|
def test_attribute_namespace_conflict
|
|
# https://www.w3.org/TR/xml-names/#uniqAttrs
|
|
message = <<-MESSAGE
|
|
Duplicate attribute "a"
|
|
Line: 4
|
|
Position: 140
|
|
Last 80 unconsumed characters:
|
|
MESSAGE
|
|
assert_raise_with_message(REXML::ParseException, message) do
|
|
Document.new(<<-XML)
|
|
<!-- http://www.w3.org is bound to n1 and n2 -->
|
|
<x xmlns:n1="http://www.w3.org"
|
|
xmlns:n2="http://www.w3.org" >
|
|
<bad a="1" a="2" />
|
|
<bad n1:a="1" n2:a="2" />
|
|
</x>
|
|
XML
|
|
end
|
|
end
|
|
|
|
def test_attribute_default_namespace
|
|
# https://www.w3.org/TR/xml-names/#uniqAttrs
|
|
document = Document.new(<<-XML)
|
|
<!-- http://www.w3.org is bound to n1 and is the default -->
|
|
<x xmlns:n1="http://www.w3.org"
|
|
xmlns="http://www.w3.org" >
|
|
<good a="1" b="2" />
|
|
<good a="1" n1:a="2" />
|
|
</x>
|
|
XML
|
|
attributes = document.root.elements.collect do |element|
|
|
element.attributes.each_attribute.collect do |attribute|
|
|
[attribute.prefix, attribute.namespace, attribute.name]
|
|
end
|
|
end
|
|
assert_equal([
|
|
[
|
|
["", "", "a"],
|
|
["", "", "b"],
|
|
],
|
|
[
|
|
["", "", "a"],
|
|
["n1", "http://www.w3.org", "a"],
|
|
],
|
|
],
|
|
attributes)
|
|
end
|
|
|
|
def test_cdata
|
|
test = "The quick brown fox jumped
|
|
& < & < \" '
|
|
over the lazy dog."
|
|
|
|
source = "<a><![CDATA[#{test}]]></a>"
|
|
d = REXML::Document.new( source )
|
|
|
|
# Test constructors
|
|
cdata = d[0][0]
|
|
assert_equal test, cdata.value
|
|
end
|
|
|
|
def test_comment
|
|
string = "This is a new comment!"
|
|
source = "<!--#{string}-->"
|
|
comment = Comment.new string
|
|
REXML::Formatters::Default.new.write( comment, out = "" )
|
|
assert_equal(source, out)
|
|
|
|
comment2 = Comment.new comment
|
|
assert_equal(comment, comment2)
|
|
|
|
assert_raise(ParseException) {
|
|
REXML::Document.new("<d><!- foo --></d>")
|
|
}
|
|
assert_raise(ParseException) {
|
|
REXML::Document.new("<d><!-- foo -></d>")
|
|
}
|
|
end
|
|
|
|
def test_whitespace
|
|
doc = Document.new "<root-element><first-element/></root-element>"
|
|
assert_equal 1, doc.root.size
|
|
assert_equal 1, doc.root.elements.size
|
|
doc = Document.new "<root-element>
|
|
<first-element/>
|
|
</root-element>"
|
|
assert_equal 3, doc.root.size
|
|
assert_equal 1, doc.root.elements.size
|
|
|
|
text = " This is text
|
|
with a lot of whitespace "
|
|
source = "<a>#{text}<b>#{text}</b><c>#{text}</c>#{text}</a>"
|
|
|
|
doc = Document.new( source, {
|
|
:respect_whitespace => %w{ a c }
|
|
} )
|
|
assert_equal text, doc.elements["//c"].text
|
|
string = ""
|
|
doc.root.each { |n| string << n.to_s if n.kind_of? Text }
|
|
assert_equal text+text, string
|
|
|
|
string =" lots of blank
|
|
space"
|
|
doc.root.add_element("d").add_element("c").text = string
|
|
doc.root.add_element("e").text = string
|
|
assert_equal string, doc.elements["/a/d/c"].text
|
|
assert string != doc.elements["/a/e"].text, "Text wasn't properly compressed"
|
|
|
|
doc = Document.new source, { :respect_whitespace => :all }
|
|
doc.root.add_element("d").text = string
|
|
assert_equal text, doc.root.text
|
|
nxt = ""
|
|
doc.root.each { |n| nxt << n.to_s if n.kind_of? Text }
|
|
assert_equal text+text, nxt
|
|
assert_equal text, doc.root.elements["b"].text
|
|
assert_equal text, doc.root.elements["c"].text
|
|
assert_equal string, doc.root.elements["d"].text
|
|
end
|
|
|
|
# This isn't complete. We need to check declarations and comments
|
|
def test_doctype
|
|
string = "something"
|
|
correct = "<!DOCTYPE something>"
|
|
doc = DocType.new(string)
|
|
assert_equal(string, doc.name)
|
|
doc.write(out="")
|
|
assert_equal(correct, out)
|
|
|
|
doc2 = DocType.new(doc)
|
|
assert_equal(doc.name, doc2.name)
|
|
assert_equal(doc.external_id, doc2.external_id)
|
|
|
|
correct = '<!DOCTYPE xsa PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" "http://www.garshol.priv.no/download/xsa/xsa.dtd">'
|
|
|
|
one_line_source = '<!DOCTYPE xsa PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML" "http://www.garshol.priv.no/download/xsa/xsa.dtd"><a/>'
|
|
doc = Document.new( one_line_source )
|
|
doc = doc[0]
|
|
assert(doc)
|
|
doc.write(test="")
|
|
assert_equal(correct, test)
|
|
|
|
multi_line_source = '<!DOCTYPE xsa PUBLIC
|
|
"-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML"
|
|
"http://www.garshol.priv.no/download/xsa/xsa.dtd">
|
|
<a/>'
|
|
d = Document.new( multi_line_source )
|
|
doc = d[0]
|
|
assert(doc)
|
|
doc.write(test="")
|
|
assert_equal(correct, test)
|
|
|
|
odd_space_source = ' <!DOCTYPE
|
|
xsa PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML"
|
|
"http://www.garshol.priv.no/download/xsa/xsa.dtd"> <a/>'
|
|
d = Document.new( odd_space_source )
|
|
dt = d.doctype
|
|
dt.write(test="")
|
|
assert_equal(correct, test)
|
|
|
|
# OK, the BIG doctype test, numba wun
|
|
doc = File.open(fixture_path("doctype_test.xml")) do |docin|
|
|
Document.new(docin)
|
|
end
|
|
doc.write(test="")
|
|
assert_equal(31, doc.doctype.size)
|
|
end
|
|
|
|
def test_document
|
|
# Testing cloning
|
|
source = "<element/>"
|
|
doc = Document.new source
|
|
|
|
# Testing Root
|
|
assert_equal doc.root.name.to_s, "element"
|
|
|
|
# Testing String source
|
|
source = @xsa_source
|
|
doc = Document.new source
|
|
assert_instance_of XMLDecl, doc.xml_decl
|
|
assert_instance_of DocType, doc.doctype
|
|
assert_equal doc.version, "1.0"
|
|
|
|
doc = File.open(fixture_path("dash.xml")) {|s| Document.new s }
|
|
assert_equal "content-2", doc.elements["//content-2"].name
|
|
end
|
|
|
|
def test_instruction
|
|
target = "use"
|
|
content = "ruby"
|
|
source = "<?#{target} #{content}?>"
|
|
|
|
instruction = Instruction.new target, content
|
|
instruction2 = Instruction.new instruction
|
|
assert_equal(instruction, instruction2)
|
|
REXML::Formatters::Default.new.write( instruction, out = "" )
|
|
assert_equal(source, out)
|
|
|
|
d = Document.new( source )
|
|
instruction2 = d[0]
|
|
assert_equal(instruction.to_s, instruction2.to_s)
|
|
|
|
assert_raise(ParseException) {
|
|
REXML::Document.new("<d><?foo bar></d>")
|
|
}
|
|
end
|
|
|
|
def test_parent
|
|
parent = Parent.new
|
|
begin
|
|
parent << "Something"
|
|
rescue Exception
|
|
parent << Comment.new("Some comment")
|
|
assert parent.size == 1, "size of parent should be 1"
|
|
else
|
|
assert_fail "should have gotten an exception trying to add a "+ "String to a Parent"
|
|
end
|
|
|
|
source = "<a><one/><three/><five/></a>"
|
|
doc = Document.new source
|
|
three = doc.root.elements["three"]
|
|
doc.root.insert_before( three, Element.new("two") )
|
|
nxt = doc.root.elements["one"]
|
|
string = ""
|
|
while nxt
|
|
string << nxt.name
|
|
nxt = nxt.next_sibling
|
|
end
|
|
assert_equal "onetwothreefive", string
|
|
|
|
|
|
doc.root.insert_after( three, Element.new("four") )
|
|
string = ""
|
|
doc.root.each { |element| string << element.name }
|
|
assert_equal "onetwothreefourfive", string
|
|
|
|
string = ""
|
|
nxt = doc.root.elements["five"]
|
|
while nxt
|
|
string << nxt.name
|
|
nxt = nxt.previous_sibling
|
|
end
|
|
assert_equal "fivefourthreetwoone", string
|
|
|
|
doc.insert_after "//two", Element.new("two-and-half")
|
|
string = doc.root.elements.collect {|x| x.name}.join
|
|
assert_equal "onetwotwo-and-halfthreefourfive", string
|
|
doc.elements["/a/five"].insert_before "../four", Element.new("three-and-half")
|
|
string = doc.root.elements.collect {|x| x.name}.join
|
|
assert_equal "onetwotwo-and-halfthreethree-and-halffourfive", string
|
|
|
|
doc.elements["/a/five"].previous_sibling = Element.new("four-and-half")
|
|
string = doc.root.elements.collect {|x| x.name}.join
|
|
assert_equal "onetwotwo-and-halfthreethree-and-halffourfour-and-halffive", string
|
|
doc.elements["/a/one"].next_sibling = Element.new("one-and-half")
|
|
string = doc.root.elements.collect {|x| x.name}.join
|
|
assert_equal "oneone-and-halftwotwo-and-halfthreethree-and-halffourfour-and-halffive", string
|
|
|
|
doc = Document.new "<a><one/><three/></a>"
|
|
doc.root[1,0] = Element.new "two"
|
|
string = ""
|
|
doc.root.each { |el| string << el.name }
|
|
assert_equal "onetwothree", string
|
|
end
|
|
|
|
# The Source classes are tested extensively throughout the test suite
|
|
def test_source
|
|
# Testing string source
|
|
source = @xsa_source
|
|
doc = Document.new source
|
|
assert_equal doc.root.name.to_s, "xsa"
|
|
|
|
# Testing IO source
|
|
doc = File.open(fixture_path("project.xml")) {|f| Document.new f }
|
|
assert_equal doc.root.name.to_s, "Project"
|
|
end
|
|
|
|
def test_text
|
|
f = REXML::Formatters::Default.new
|
|
string = "Some text"
|
|
text = Text.new(string)
|
|
assert_equal(string, text.to_s)
|
|
text2 = Text.new(text)
|
|
assert_equal(text, text2)
|
|
#testing substitution
|
|
string = "0 < ( 1 & 1 )"
|
|
correct = "0 < ( 1 & 1 )"
|
|
text = Text.new(string, true)
|
|
f.write(text,out="")
|
|
assert_equal(correct, out)
|
|
|
|
string = "Cats & dogs"
|
|
text = Text.new(string, false, nil, true)
|
|
assert_equal(string, text.to_s)
|
|
|
|
string2 = "<a>#{string}</a>"
|
|
doc = Document.new( string2, {
|
|
:raw => %w{ a b }
|
|
} )
|
|
f.write(doc,out="")
|
|
assert_equal(string2, out)
|
|
b = doc.root.add_element( "b" )
|
|
b.text = string
|
|
assert_equal(string, b.get_text.to_s)
|
|
|
|
c = doc.root.add_element("c")
|
|
c.text = string
|
|
assert_equal("Cats &amp; dogs", c.get_text.to_s)
|
|
|
|
# test all
|
|
string = "<a>&<b><</b><c>><d>"</d></c></a>"
|
|
doc = Document.new(string, { :raw => :all })
|
|
assert_equal( "&", doc.elements["/a"][0].to_s )
|
|
assert_equal( "&", doc.elements["/a"].text )
|
|
assert_equal( "<", doc.elements["/a/b"][0].to_s )
|
|
assert_equal( "<", doc.elements["/a/b"].text )
|
|
assert_equal( ">", doc.elements["/a/c"][0].to_s )
|
|
assert_equal( ">", doc.elements["/a/c"].text )
|
|
assert_equal( '"', doc.elements["//d"][0].to_s )
|
|
assert_equal( '"', doc.elements["//d"].text )
|
|
|
|
# test some other stuff
|
|
doc = Document.new('<a><b/></a>')
|
|
doc.root.text = 'Sean'
|
|
assert_equal( '<a><b/>Sean</a>', doc.to_s )
|
|
doc.root.text = 'Elliott'
|
|
assert_equal( '<a><b/>Elliott</a>', doc.to_s )
|
|
doc.root.add_element( 'c' )
|
|
assert_equal( '<a><b/>Elliott<c/></a>', doc.to_s )
|
|
doc.root.text = 'Russell'
|
|
assert_equal( '<a><b/>Russell<c/></a>', doc.to_s )
|
|
doc.root.text = nil
|
|
assert_equal( '<a><b/><c/></a>', doc.to_s )
|
|
end
|
|
|
|
def test_text_frozen
|
|
string = "Frozen".freeze
|
|
text = Text.new(string)
|
|
assert_equal(string, text.to_s)
|
|
end
|
|
|
|
def test_xmldecl
|
|
source = "<?xml version='1.0'?>"
|
|
# test args
|
|
# test no args
|
|
decl2 = XMLDecl.new
|
|
assert_equal source, decl2.to_s
|
|
# test XMLDecl
|
|
decl2 = XMLDecl.new "1.0"
|
|
assert_equal source, decl2.to_s
|
|
end
|
|
|
|
def test_xmldecl_utf_16be_encoding_name
|
|
assert_equal("<?xml version='1.0' encoding='UTF-16'?>",
|
|
XMLDecl.new("1.0", "UTF-16").to_s)
|
|
end
|
|
|
|
def each_test( element, xpath, num_children )
|
|
count = 0
|
|
element.each_element( xpath ) { |child|
|
|
count += 1
|
|
yield child if block_given?
|
|
}
|
|
assert_equal num_children, count
|
|
end
|
|
|
|
# This is the biggest test, as the number of permutations of xpath are
|
|
# enormous.
|
|
def test_element_access
|
|
# Testing each_element
|
|
doc = File.open(fixture_path("project.xml")) {|f| Document.new f }
|
|
|
|
each_test( doc, "/", 1 ) { |child|
|
|
assert_equal doc.name, child.name
|
|
}
|
|
each_test(doc, ".", 1) { |child| assert_equal doc, child }
|
|
each_test(doc.root, "..", 1) { |child| assert_equal doc, child }
|
|
each_test(doc.root, "*", 5)
|
|
each_test(doc, "Project/Datasets", 1) { |child|
|
|
assert_equal "Datasets", child.name
|
|
}
|
|
each_test(doc, "Project/Datasets/link", 2 )
|
|
each_test(doc.root, "/Project/Description", 1) {|child|
|
|
assert_equal "Description", child.name
|
|
}
|
|
each_test(doc.root, "./Description",1 ) { |child|
|
|
assert_equal "Description",child.name
|
|
}
|
|
each_test(doc.root, "../Project",1 ) { |child|
|
|
assert_equal doc.root, child
|
|
}
|
|
#each_test(doc,".../link",2) {|child| assert_equal "link",child.name.to_s}
|
|
|
|
# test get_element
|
|
first = doc.elements[ "Project" ]
|
|
assert_equal doc.root, first
|
|
second = doc.elements[ "Project" ].elements[1]
|
|
third = doc.elements[ "Project/Creator" ]
|
|
assert_equal second, third
|
|
fourth = doc.elements[ "Project/Datasets/link[@idref='18']" ]
|
|
assert_equal "Test data 1", fourth.attributes["name"]
|
|
|
|
# Testing each_predicate
|
|
each_test( doc, "Project/Datasets/link[@idref='18']", 1 ) { |child|
|
|
assert_equal "Test data 1", child.attributes["name"]
|
|
}
|
|
|
|
# testing next/previous_element
|
|
creator = doc.elements["//Creator"]
|
|
lm = creator.next_element
|
|
assert_equal "LastModifier", lm.name
|
|
assert_equal "Creator", lm.previous_element.name
|
|
end
|
|
|
|
def test_child
|
|
sean = Element.new "Sean"
|
|
rubbell = Element.new "Rubbell"
|
|
elliott = sean.add_element "Elliott"
|
|
sean << rubbell
|
|
assert_equal elliott, rubbell.previous_sibling
|
|
assert_equal rubbell, elliott.next_sibling
|
|
|
|
russell = Element.new "Russell"
|
|
rubbell.replace_with russell
|
|
assert_equal elliott, russell.previous_sibling
|
|
assert_equal russell, elliott.next_sibling
|
|
|
|
assert_nil russell.document
|
|
assert_equal sean, russell.root
|
|
end
|
|
|
|
# Most of this class is tested elsewhere. Here are the methods which
|
|
# aren't used in any other class
|
|
def test_element
|
|
sean = Element.new "Sean"
|
|
string = "1) He's a great guy!"
|
|
sean.text = string
|
|
russell = Element.new "Russell"
|
|
sean << russell
|
|
|
|
russell.attributes["email"] = "ser@germane-software.com"
|
|
assert_equal russell.attributes["email"], "ser@germane-software.com"
|
|
russell.attributes["webpage"] = "http://www.germane-software.com/~ser"
|
|
|
|
assert sean.has_text?, "element should have text"
|
|
assert_equal sean.text, string
|
|
assert sean.has_elements?, "element should have one element"
|
|
string = "2) What a stud!"
|
|
sean.add_text string
|
|
sean.text = "3) Super programmer!"
|
|
sean.text = nil
|
|
assert sean.has_text?, "element should still have text"
|
|
assert_equal sean.text, string
|
|
|
|
russell.delete_attribute "email"
|
|
assert_nil russell.attributes["email"]
|
|
russell.attributes.delete "webpage"
|
|
assert !russell.has_attributes?, "element should have no attributes"
|
|
end
|
|
|
|
def test_no_format
|
|
source = "<a><b><c>blah</c><d/></b></a>"
|
|
out = ""
|
|
doc = Document.new( source )
|
|
doc.write(out)
|
|
assert_equal(source, out)
|
|
end
|
|
|
|
def test_namespace
|
|
source = <<-EOF
|
|
<x xmlns:foo="http://www.bar.com/schema">
|
|
</x>
|
|
EOF
|
|
doc = Document.new(source)
|
|
assert_equal("http://www.bar.com/schema", doc.root.namespace( "foo" ))
|
|
source = <<-EOF
|
|
<!-- bar namespace is "someuri" -->
|
|
<foo:bar xmlns="default" xmlns:foo="someuri">
|
|
<!-- a namespace is "default" -->
|
|
<a/>
|
|
<!-- foo:b namespace is "someuri" -->
|
|
<foo:b>
|
|
<!-- c namespace is "default" -->
|
|
<c/>
|
|
</foo:b>
|
|
<!-- d namespace is "notdefault" -->
|
|
<d xmlns="notdefault">
|
|
<!-- e namespace is "notdefault" -->
|
|
<e/>
|
|
<f xmlns="">
|
|
<g/>
|
|
</f>
|
|
</d>
|
|
</foo:bar>
|
|
EOF
|
|
doc = Document.new source
|
|
assert_equal "someuri", doc.root.namespace
|
|
assert_equal "default", doc.root.elements[1].namespace
|
|
assert_equal "someuri", doc.root.elements[2].namespace
|
|
assert_equal "notdefault", doc.root.elements[ 3 ].namespace
|
|
|
|
# Testing namespaces in attributes
|
|
source = <<-EOF
|
|
<a xmlns:b="uri">
|
|
<b b:a="x" a="y"/>
|
|
<c xmlns="foo">
|
|
</c>
|
|
</a>
|
|
EOF
|
|
doc = Document.new source
|
|
b = doc.root.elements["b"]
|
|
assert_equal "x", b.attributes["b:a"]
|
|
assert_equal "y", b.attributes["a"]
|
|
|
|
doc = Document.new
|
|
doc.add_element "sean:blah"
|
|
doc.root.text = "Some text"
|
|
out = ""
|
|
doc.write(out)
|
|
assert_equal "<sean:blah>Some text</sean:blah>", out
|
|
end
|
|
|
|
|
|
def test_add_namespace
|
|
e = Element.new 'a'
|
|
e.add_namespace 'someuri'
|
|
e.add_namespace 'foo', 'otheruri'
|
|
e.add_namespace 'xmlns:bar', 'thirduri'
|
|
assert_equal 'someuri', e.attributes['xmlns']
|
|
assert_equal 'otheruri', e.attributes['xmlns:foo']
|
|
assert_equal 'thirduri', e.attributes['xmlns:bar']
|
|
end
|
|
|
|
|
|
def test_big_documentation
|
|
d = File.open(fixture_path("documentation.xml")) {|f| Document.new f }
|
|
assert_equal "Sean Russell", d.elements["documentation/head/author"].text.tr("\n\t", " ").squeeze(" ")
|
|
out = ""
|
|
d.write out
|
|
end
|
|
|
|
def test_tutorial
|
|
doc = File.open(fixture_path("tutorial.xml")) {|f| Document.new f }
|
|
out = ""
|
|
doc.write out
|
|
end
|
|
|
|
def test_stream
|
|
c = Listener.new
|
|
File.open(fixture_path("documentation.xml")) do |f|
|
|
Document.parse_stream( f, c )
|
|
end
|
|
assert(c.ts, "Stream parsing apparently didn't parse the whole file")
|
|
assert(c.te, "Stream parsing dropped end tag for documentation")
|
|
|
|
Document.parse_stream("<a.b> <c/> </a.b>", c)
|
|
|
|
Document.parse_stream("<a><>&</a>", c)
|
|
assert_equal('<>&', c.normalize)
|
|
end
|
|
|
|
def test_line
|
|
f = File.new(fixture_path("bad.xml"))
|
|
Document.new f
|
|
assert_fail "There should have been an error"
|
|
rescue Exception
|
|
# We should get here
|
|
assert($!.line == 5, "Should have been an error on line 5, "+
|
|
"but was reported as being on line #{$!.line}" )
|
|
ensure
|
|
f.close if f
|
|
end
|
|
|
|
def test_substitution
|
|
val = "a'b\"c"
|
|
el = Element.new("a")
|
|
el.attributes["x"] = val
|
|
REXML::Formatters::Default.new.write(el, out="")
|
|
|
|
nel = Document.new( out)
|
|
assert_equal( val, nel.root.attributes["x"] )
|
|
end
|
|
|
|
def test_exception
|
|
source = SourceFactory.create_from "<a/>"
|
|
p = ParseException.new( "dummy message", source )
|
|
begin
|
|
raise "dummy"
|
|
rescue Exception
|
|
p.continued_exception = $!
|
|
end
|
|
end
|
|
|
|
def test_bad_content
|
|
in_gt = '<root-el>content>content</root-el>'
|
|
in_lt = '<root-el>content<content</root-el>'
|
|
|
|
# This is OK
|
|
tree_gt = Document.new in_gt
|
|
assert_equal "content>content", tree_gt.elements[1].text
|
|
# This isn't
|
|
begin
|
|
Document.new in_lt
|
|
assert_fail "Should have gotten a parse error"
|
|
rescue ParseException
|
|
end
|
|
end
|
|
|
|
def test_iso_8859_1_output_function
|
|
out = ""
|
|
output = Output.new( out )
|
|
koln_iso_8859_1 = "K\xF6ln"
|
|
koln_utf8 = "K\xc3\xb6ln"
|
|
source = Source.new( koln_iso_8859_1, 'iso-8859-1' )
|
|
results = source.scan(/.*/)[0]
|
|
koln_utf8.force_encoding('UTF-8') if koln_utf8.respond_to?(:force_encoding)
|
|
assert_equal koln_utf8, results
|
|
output << results
|
|
if koln_iso_8859_1.respond_to?(:force_encoding)
|
|
koln_iso_8859_1.force_encoding('ISO-8859-1')
|
|
end
|
|
assert_equal koln_iso_8859_1, out
|
|
end
|
|
|
|
def test_attributes_each
|
|
doc = Document.new("<a xmlns:a='foo'><b x='1' y='2' z='3' a:x='4'/></a>")
|
|
count = 0
|
|
doc.root.elements[1].attributes.each {|k,v| count += 1 }
|
|
assert_equal 4, count
|
|
end
|
|
|
|
def test_delete_namespace
|
|
doc = Document.new "<a xmlns='1' xmlns:x='2'/>"
|
|
doc.root.delete_namespace
|
|
doc.root.delete_namespace 'x'
|
|
assert_equal "<a/>", doc.to_s
|
|
end
|
|
|
|
def test_each_element_with_attribute
|
|
doc = Document.new "<a><b id='1'/><c id='2'/><d id='1'/><e/></a>"
|
|
arry = []
|
|
block = proc { |e|
|
|
assert arry.include?(e.name)
|
|
arry.delete e.name
|
|
}
|
|
# Yields b, c, d
|
|
arry = %w{b c d}
|
|
doc.root.each_element_with_attribute( 'id', &block )
|
|
assert_equal 0, arry.size
|
|
# Yields b, d
|
|
arry = %w{b d}
|
|
doc.root.each_element_with_attribute( 'id', '1', &block )
|
|
assert_equal 0, arry.size
|
|
# Yields b
|
|
arry = ['b']
|
|
doc.root.each_element_with_attribute( 'id', '1', 1, &block )
|
|
assert_equal 0, arry.size
|
|
# Yields d
|
|
arry = ['d']
|
|
doc.root.each_element_with_attribute( 'id', '1', 0, 'd', &block )
|
|
assert_equal 0, arry.size
|
|
end
|
|
def test_each_element_with_text
|
|
doc = Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>'
|
|
arry = []
|
|
block = proc { |e|
|
|
assert arry.include?(e.name)
|
|
arry.delete e.name
|
|
}
|
|
# Yields b, c, d
|
|
arry = %w{b c d}
|
|
doc.root.each_element_with_text(&block)
|
|
assert_equal 0, arry.size
|
|
# Yields b, d
|
|
arry = %w{b c}
|
|
doc.root.each_element_with_text( 'b', &block )
|
|
assert_equal 0, arry.size
|
|
# Yields b
|
|
arry = ['b']
|
|
doc.root.each_element_with_text( 'b', 1, &block )
|
|
assert_equal 0, arry.size
|
|
# Yields d
|
|
arry = ['d']
|
|
doc.root.each_element_with_text( nil, 0, 'd', &block )
|
|
assert_equal 0, arry.size
|
|
end
|
|
|
|
def test_element_parse_stream
|
|
s = Source.new( "<a>some text</a>" )
|
|
l = Listener.new
|
|
class << l
|
|
def tag_start name, attributes
|
|
raise "Didn't find proper tag name" unless 'a'==name
|
|
end
|
|
end
|
|
|
|
Document::parse_stream(s, l)
|
|
end
|
|
|
|
def test_deep_clone
|
|
a = Document.new( '<?xml version="1"?><a x="y"><b>text</b>text<c><d><e>text</e></d></c></a>' )
|
|
b = a.deep_clone
|
|
assert_equal a.to_s, b.to_s
|
|
|
|
a = Document.new( '<a>some < text <b> more > text </b> > </a>' )
|
|
b = a.deep_clone
|
|
assert_equal a.to_s, b.to_s
|
|
c = Document.new( b.to_s )
|
|
assert_equal a.to_s, c.to_s
|
|
end
|
|
|
|
def test_whitespace_before_root
|
|
a = <<EOL
|
|
<?xml version='1.0'?>
|
|
<blo>
|
|
<wak>
|
|
</wak>
|
|
</blo>
|
|
EOL
|
|
d = Document.new(a)
|
|
b = ""
|
|
d.write( b )
|
|
assert_equal a,b
|
|
end
|
|
|
|
def test_entities
|
|
a = Document.new( '<a>eeü</a>' )
|
|
assert_equal('eeü'.force_encoding("UTF-8"), a.root.text)
|
|
end
|
|
|
|
def test_element_decl
|
|
element_decl = Source.new("<!DOCTYPE foo [
|
|
<!ELEMENT bar (#PCDATA)>
|
|
]>")
|
|
doc = Document.new( element_decl )
|
|
d = doc[0]
|
|
assert_equal("<!ELEMENT bar (#PCDATA)>", d.to_s.split(/\n/)[1].strip)
|
|
end
|
|
|
|
def test_attlist_decl
|
|
doc = Document.new <<-EOL
|
|
<!DOCTYPE blah [
|
|
<!ATTLIST blah
|
|
xmlns CDATA "foo">
|
|
<!ATTLIST a
|
|
bar CDATA "gobble"
|
|
xmlns:one CDATA "two"
|
|
>
|
|
]>
|
|
<a xmlns:three='xxx' three='yyy'><one:b/><three:c/></a>
|
|
EOL
|
|
assert_equal 'gobble', doc.root.attributes['bar']
|
|
assert_equal 'xxx', doc.root.elements[2].namespace
|
|
assert_equal 'two', doc.root.elements[1].namespace
|
|
assert_equal 'foo', doc.root.namespace
|
|
|
|
doc = Document.new <<-EOL
|
|
<?xml version="1.0"?>
|
|
<!DOCTYPE schema SYSTEM "XMLSchema.dtd" [
|
|
<!ENTITY % p ''>
|
|
<!ENTITY % s ''>
|
|
<!ATTLIST schema
|
|
xmlns:svg CDATA #FIXED "http://www.w3.org/2000/svg"
|
|
xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink"
|
|
xmlns:xml CDATA #FIXED "http://www.w3.org/XML/1998/namespace"
|
|
>]>
|
|
<schema/>
|
|
EOL
|
|
prefixes = doc.root.prefixes.sort
|
|
correct = ['svg', 'xlink', 'xml']
|
|
assert_equal correct, prefixes
|
|
end
|
|
|
|
def test_attlist_write
|
|
doc = File.open(fixture_path("foo.xml")) {|file| Document.new file }
|
|
out = ''
|
|
doc.write(out)
|
|
end
|
|
|
|
def test_more_namespaces
|
|
assert_raise( REXML::UndefinedNamespaceException,
|
|
%Q{Should have gotten an Undefined Namespace error} ) {
|
|
Document.new("<r><p><n:c/></p></r>")
|
|
}
|
|
doc2 = Document.new("<r xmlns:n='1'><p><n:c/></p></r>")
|
|
es = XPath.match(doc2, '//c')
|
|
assert_equal 0, es.size
|
|
es = XPath.match(doc2, '//n:c')
|
|
assert_equal 1, es.size
|
|
doc2.root.add_namespace('m', '2')
|
|
doc2.root.add_element("m:o")
|
|
es = XPath.match(doc2, './/o')
|
|
assert_equal 0, es.size
|
|
es = XPath.match(doc2, '//n:c')
|
|
assert_equal 1, es.size
|
|
end
|
|
|
|
def test_ticket_51
|
|
doc = REXML::Document.new <<-EOL
|
|
<test xmlns='1' xmlns:x='1'>
|
|
<a>X</a>
|
|
<x:a>Y</x:a>
|
|
|
|
<b xmlns='2'>
|
|
<a>Z</a>
|
|
</b>
|
|
</test>
|
|
EOL
|
|
|
|
# The most common case. People not caring about the namespaces much.
|
|
assert_equal( "XY", XPath.match( doc, "/*:test/*:a/text()" ).join )
|
|
assert_equal( "XY", XPath.match( doc, "/*:test/x:a/text()" ).join )
|
|
# Surprising? I don't think so, if you believe my definition of the "common case"
|
|
assert_equal( "XYZ", XPath.match( doc, "//*:a/text()" ).join )
|
|
|
|
# These are the uncommon cases. Namespaces are actually important, so we define our own
|
|
# mappings, and pass them in.
|
|
assert_equal( "XY", XPath.match( doc, "/f:test/f:a/text()", { "f" => "1" } ).join )
|
|
# The namespaces are defined, and override the original mappings
|
|
assert_equal( "XY", XPath.match( doc, "/*:test/*:a/text()", { "f" => "1" } ).join )
|
|
assert_equal( "", XPath.match( doc, "/x:test/x:a/text()", { "f" => "1" } ).join )
|
|
assert_equal( "XYZ", XPath.match( doc, "//*:a/text()", { "f" => "1" } ).join )
|
|
end
|
|
|
|
def test_processing_instruction
|
|
d = Document.new("<a><?foo bar?><?foo2 bar2?><b><?foo3 bar3?></b><?foo4 bar4?></a>")
|
|
assert_equal 4, XPath.match(d, '//processing-instruction()' ).size
|
|
match = XPath.match(d, "//processing-instruction('foo3')" )
|
|
assert_equal 1, match.size
|
|
assert_equal 'bar3', match[0].content
|
|
end
|
|
|
|
def test_oses_with_bad_EOLs
|
|
Document.new("\n\n\n<?xml version='1.0'?>\n\n\n<a/>\n\n")
|
|
end
|
|
|
|
# Contributed (with patch to fix bug) by Kouhei
|
|
def test_ignore_whitespace
|
|
source = "<a> <b/> abc <![CDATA[def]]> </a>"
|
|
|
|
context_all = {:ignore_whitespace_nodes => :all}
|
|
context_a = {:ignore_whitespace_nodes => %(a)}
|
|
context_b = {:ignore_whitespace_nodes => %(b)}
|
|
|
|
tests = [[[" abc ", "def"], context_all],
|
|
[[" abc ", "def"], context_a],
|
|
[[" ", " abc ", "def", " "], context_b]]
|
|
|
|
tests.each do |test|
|
|
assert_equal(test[0], Document.new(source, test[1]).root.texts.collect{|x|
|
|
x.to_s})
|
|
end
|
|
end
|
|
|
|
def test_0xD_in_preface
|
|
doc = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\x0D<opml version=\"1.0\">\x0D</opml>"
|
|
doc = Document.new doc
|
|
end
|
|
|
|
def test_hyphens_in_doctype
|
|
doc = REXML::Document.new <<-EOQ
|
|
<?xml version="1.0"?>
|
|
<!DOCTYPE a-b-c>
|
|
<a-b-c>
|
|
<a/>
|
|
</a-b-c>
|
|
EOQ
|
|
|
|
assert_equal('a-b-c', doc.doctype.name)
|
|
end
|
|
|
|
def test_accents
|
|
docs = [
|
|
%Q{<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
<gnuPod>
|
|
<files>
|
|
<file id="57" artist="Coralie Cl\357\277\275ent" />
|
|
</files>
|
|
</gnuPod>},
|
|
'<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
<gnuPod>
|
|
<files>
|
|
<file id="71" album="Astrakan Caf" />
|
|
</files>
|
|
</gnuPod>',
|
|
%Q{<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
<gnuPod>
|
|
<files>
|
|
<file id="71" album="Astrakan Caf\357\277\275eria" />
|
|
</files>
|
|
</gnuPod>},
|
|
%Q{<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
<gnuPod>
|
|
<files>
|
|
<file id="71" album="Astrakan Caf\357\277\275" />
|
|
</files>
|
|
</gnuPod>} ]
|
|
docs.each_with_index { |d,i|
|
|
begin
|
|
REXML::Document.new(d)
|
|
rescue
|
|
puts "#{i} => #{docs[i]}"
|
|
raise
|
|
end
|
|
}
|
|
end
|
|
|
|
def test_replace_text
|
|
e = REXML::Element.new( "a" )
|
|
e.add_text( "foo" )
|
|
assert_equal( "<a>foo</a>", e.to_s )
|
|
e[0].value = "bar"
|
|
assert_equal( "<a>bar</a>", e.to_s )
|
|
e[0].value = "<"
|
|
assert_equal( "<a><</a>", e.to_s )
|
|
assert_equal( "<", e[0].value )
|
|
end
|
|
|
|
|
|
def test_write_doctype
|
|
## XML Document and Declaration
|
|
document = REXML::Document.new
|
|
xmldecl = REXML::XMLDecl.new("1.0", "UTF-8")
|
|
document.add(xmldecl)
|
|
s = ""
|
|
document.write(s)
|
|
|
|
## XML Doctype
|
|
str = '<!DOCTYPE foo "bar">'
|
|
source = REXML::Source.new(str)
|
|
doctype = REXML::DocType.new(source)
|
|
document.add(doctype)
|
|
document.write(s)
|
|
|
|
## Element
|
|
element = REXML::Element.new("hoge")
|
|
document.add(element)
|
|
|
|
document.write(s)
|
|
end
|
|
|
|
def test_write_cdata
|
|
src = "<a>A</a>"
|
|
doc = REXML::Document.new( src )
|
|
out = ""
|
|
doc.write( out )
|
|
assert_equal( src, out )
|
|
|
|
src = "<a><![CDATA[A]]></a>"
|
|
doc = REXML::Document.new( src )
|
|
out = ""
|
|
doc.write( out )
|
|
assert_equal( src, out )
|
|
end
|
|
|
|
def test_namespace_attributes
|
|
source = <<-EOL
|
|
<a xmlns:x="1">
|
|
<x:b x:n="foo"/>
|
|
</a>
|
|
EOL
|
|
d = Document.new( source )
|
|
assert_equal( 'foo', REXML::XPath.first(d.root, "//x:b/@x:n").value )
|
|
assert_equal( nil, REXML::XPath.first(d.root, "//x:b/@x:n", {}))
|
|
end
|
|
|
|
def test_null_element_name
|
|
a = REXML::Document.new
|
|
assert_raise( RuntimeError ) {
|
|
a.add_element( nil )
|
|
}
|
|
end
|
|
|
|
def test_text_raw
|
|
# From the REXML tutorial
|
|
# (http://www.germane-software.com/software/rexml/test/data/tutorial.html)
|
|
doc = Document.new <<-EOL
|
|
<?xml version="1.0"?>
|
|
<!DOCTYPE schema SYSTEM "XMLSchema.dtd" [
|
|
<!ENTITY % s 'Sean'>
|
|
]>
|
|
<a/>
|
|
EOL
|
|
a = doc.root
|
|
|
|
# This makes sure that RAW text nodes don't have their entity strings
|
|
# replaced
|
|
t = Text.new "Sean", false, nil, true
|
|
a.text = t
|
|
assert_equal( "Sean", t.to_s )
|
|
assert_equal( "Sean", t.value )
|
|
|
|
# This makes sure that they do
|
|
t = Text.new "Sean", false, nil, false
|
|
a.text = t
|
|
assert_equal( "&s;", t.to_s )
|
|
assert_equal( "Sean", t.value )
|
|
|
|
t = Text.new "&s;", false, nil, true
|
|
a.text = t
|
|
assert_equal( "&s;", t.to_s )
|
|
assert_equal( "Sean", t.value )
|
|
|
|
t = Text.new "&s;", false, nil, true
|
|
a.text = t
|
|
assert_equal( "&s;", t.to_s )
|
|
assert_equal( "Sean", t.value )
|
|
|
|
# Ticket #44
|
|
t = REXML::Text.new( "&", false, nil, true )
|
|
assert_equal( "&", t.to_s )
|
|
|
|
t = REXML::Text.new("&", false, false)
|
|
assert_equal( "&amp;", t.to_s )
|
|
end
|
|
|
|
def test_to_xpath
|
|
doc = REXML::Document.new( %q{<tag1>
|
|
<tag2 name="tag2"/>
|
|
<tag2 name="tag2"/>
|
|
</tag1>})
|
|
names = %w{ /tag1/tag2[1] /tag1/tag2[2] }
|
|
doc.root.elements.each_with_index {|el, i|
|
|
assert_equal( names[i], el.xpath )
|
|
}
|
|
end
|
|
|
|
def test_transitive
|
|
doc = REXML::Document.new( "<a/>")
|
|
s = ""
|
|
doc.write( s, 0, true )
|
|
end
|
|
|
|
# This is issue #40
|
|
def test_replace_with
|
|
old = '<doc>old<foo/>old</doc>'
|
|
d = REXML::Document.new(old).root
|
|
new = REXML::Text.new('new',true,nil,true)
|
|
child = d.children[2]
|
|
child.replace_with(new)
|
|
assert_equal( new, d.children[2] )
|
|
end
|
|
|
|
def test_repeated_writes
|
|
a = IO.read(fixture_path("iso8859-1.xml"))
|
|
f = REXML::Formatters::Pretty.new
|
|
|
|
xmldoc = REXML::Document.new( a )
|
|
a_andre = xmldoc.elements['//image'].attributes['caption']
|
|
|
|
f.write(xmldoc,b="")
|
|
|
|
xmldoc = REXML::Document.new(b)
|
|
b_andre = xmldoc.elements['//image'].attributes['caption']
|
|
assert_equal( a_andre, b_andre )
|
|
|
|
f.write(xmldoc,c="")
|
|
|
|
xmldoc = REXML::Document.new(c)
|
|
c_andre = xmldoc.elements['//image'].attributes['caption']
|
|
assert_equal( b_andre, c_andre )
|
|
|
|
o = Output.new(d="","UTF-8")
|
|
f.write(xmldoc,o)
|
|
assert_not_equal( c, d )
|
|
end
|
|
|
|
def test_pretty_format_long_text_finite
|
|
n = 1_000_000
|
|
long_text = 'aaaa ' * n
|
|
xml = "<doc>#{long_text}</doc>"
|
|
formatter = REXML::Formatters::Pretty.new
|
|
document = nil
|
|
begin
|
|
document = REXML::Document.new(xml)
|
|
rescue REXML::ParseException
|
|
skip_message = "skip this test because we can't check Pretty#wrap " +
|
|
"works without #<SystemStackError: stack level too deep> on " +
|
|
"small memory system. #<RegexpError: failed to allocate memory> " +
|
|
"will be raised on the system. See also [ruby-dev:42599]."
|
|
return skip_message
|
|
end
|
|
output = ""
|
|
formatter.write(document, output)
|
|
assert_equal("<doc>\n" +
|
|
((" " + (" aaaa" * 15) + "\n") * (n / 15)) +
|
|
" " + ("aaaa " * (n % 15)) + "\n" +
|
|
"</doc>",
|
|
output)
|
|
end
|
|
|
|
def test_pretty_format_deep_indent
|
|
n = 6
|
|
elements = ""
|
|
n.times do |i|
|
|
elements << "<element#{i}>"
|
|
elements << "element#{i} " * 5
|
|
end
|
|
(n - 1).downto(0) do |i|
|
|
elements << "</element#{i}>"
|
|
end
|
|
xml = "<doc>#{elements}</doc>"
|
|
document = REXML::Document.new(xml)
|
|
formatter = REXML::Formatters::Pretty.new
|
|
formatter.width = 20
|
|
output = ""
|
|
formatter.write(document, output)
|
|
assert_equal(<<-XML.strip, output)
|
|
<doc>
|
|
<element0>
|
|
element0
|
|
element0
|
|
element0
|
|
element0
|
|
element0\s
|
|
<element1>
|
|
element1
|
|
element1
|
|
element1
|
|
element1
|
|
element1\s
|
|
<element2>
|
|
element2
|
|
element2
|
|
element2
|
|
element2
|
|
element2\s
|
|
<element3>
|
|
element3
|
|
element3
|
|
element3
|
|
element3
|
|
element3\s
|
|
<element4>
|
|
element4
|
|
element4
|
|
element4
|
|
element4
|
|
element4
|
|
\s
|
|
<element5>
|
|
element5 element5 element5 element5 element5\s
|
|
</element5>
|
|
</element4>
|
|
</element3>
|
|
</element2>
|
|
</element1>
|
|
</element0>
|
|
</doc>
|
|
XML
|
|
end
|
|
|
|
def test_ticket_58
|
|
doc = REXML::Document.new
|
|
doc << REXML::XMLDecl.default
|
|
doc << REXML::Element.new("a")
|
|
|
|
str = ""
|
|
doc.write(str)
|
|
|
|
assert_equal("<a/>", str)
|
|
|
|
doc = REXML::Document.new
|
|
doc << REXML::XMLDecl.new("1.0", "UTF-8")
|
|
doc << REXML::Element.new("a")
|
|
|
|
str = ""
|
|
doc.write(str)
|
|
|
|
assert_equal("<?xml version='1.0' encoding='UTF-8'?><a/>", str)
|
|
end
|
|
|
|
# Incomplete tags should generate an error
|
|
def test_ticket_53
|
|
assert_raise( REXML::ParseException ) {
|
|
REXML::Document.new( "<a><b></a>" )
|
|
}
|
|
assert_raise( REXML::ParseException ) {
|
|
REXML::Document.new( "<a><b>" )
|
|
}
|
|
assert_raise( REXML::ParseException ) {
|
|
REXML::Document.new( "<a><b/>" )
|
|
}
|
|
end
|
|
|
|
def test_ticket_52
|
|
source = "<!-- this is a single line comment -->"
|
|
d = REXML::Document.new(source)
|
|
d.write(k="")
|
|
assert_equal( source, k )
|
|
|
|
source = "<a><!-- Comment --></a>"
|
|
target = "<a>\n <!-- Comment -->\n</a>"
|
|
d = REXML::Document.new(source)
|
|
REXML::Formatters::Pretty.new(4).write(d,k="")
|
|
assert_equal( target, k )
|
|
end
|
|
|
|
def test_ticket_76
|
|
src = "<div>at&t"
|
|
assert_raise( ParseException, %Q{"#{src}" is invalid XML} ) {
|
|
REXML::Document.new(src)
|
|
}
|
|
end
|
|
|
|
def test_ticket_21
|
|
src = "<foo bar=value/>"
|
|
exception = assert_raise(ParseException) do
|
|
Document.new(src)
|
|
end
|
|
assert_equal(<<-DETAIL, exception.to_s)
|
|
Missing attribute value start quote: <bar>
|
|
Line: 1
|
|
Position: 16
|
|
Last 80 unconsumed characters:
|
|
DETAIL
|
|
end
|
|
|
|
def test_ticket_63
|
|
File.open(fixture_path("t63-1.xml")) {|f| Document.new(f) }
|
|
end
|
|
|
|
def test_ticket_75
|
|
d = File.open(fixture_path("t75.xml")) {|f| REXML::Document.new(f) }
|
|
assert_equal("tree", d.root.name)
|
|
end
|
|
|
|
def test_ticket_48_part_II
|
|
f = REXML::Formatters::Pretty.new
|
|
#- rexml sanity check (bugs in ruby 1.8.4, ruby 1.8.6)
|
|
xmldoc = Document.new("<test/>")
|
|
xmldoc << XMLDecl.new(XMLDecl::DEFAULT_VERSION, "UTF-8")
|
|
content = ['61c3a927223c3e26'].pack("H*")
|
|
content.force_encoding('UTF-8') if content.respond_to?(:force_encoding)
|
|
#- is some UTF-8 text but just to make sure my editor won't magically convert..
|
|
xmldoc.root.add_attribute('attr', content)
|
|
f.write(xmldoc,out=[])
|
|
|
|
xmldoc = REXML::Document.new(out.join)
|
|
sanity1 = xmldoc.root.attributes['attr']
|
|
f.write(xmldoc,out=[])
|
|
|
|
xmldoc = REXML::Document.new(out.join)
|
|
sanity2 = xmldoc.root.attributes['attr']
|
|
f.write(xmldoc,out=[])
|
|
|
|
assert_equal( sanity1, sanity2 )
|
|
end
|
|
|
|
def test_ticket_88
|
|
doc = REXML::Document.new("<?xml version=\"1.0\" encoding=\"shift_jis\"?>")
|
|
assert_equal("<?xml version='1.0' encoding='SHIFT_JIS'?>", doc.to_s)
|
|
doc = REXML::Document.new("<?xml version = \"1.0\" encoding = \"shift_jis\"?>")
|
|
assert_equal("<?xml version='1.0' encoding='SHIFT_JIS'?>", doc.to_s)
|
|
end
|
|
|
|
def test_ticket_85
|
|
xml = <<ENDXML
|
|
<foo>
|
|
<bar>
|
|
<bob name='jimmy'/>
|
|
</bar>
|
|
</foo>
|
|
ENDXML
|
|
|
|
yml = "<foo>
|
|
<bar>
|
|
<bob name='jimmy'/>
|
|
</bar>
|
|
</foo>"
|
|
|
|
# The pretty printer ignores all whitespace, anyway so output1 == output2
|
|
f = REXML::Formatters::Pretty.new( 2 )
|
|
d = Document.new( xml, :ignore_whitespace_nodes=>:all )
|
|
f.write( d, output1="" )
|
|
|
|
d = Document.new( xml )
|
|
f.write( d, output2="" )
|
|
|
|
# Output directives should override whitespace directives.
|
|
assert_equal( output1, output2 )
|
|
|
|
# The base case.
|
|
d = Document.new(yml)
|
|
f.write( d, output3="" )
|
|
|
|
assert_equal( output3.strip, output2.strip )
|
|
|
|
d = Document.new(yml)
|
|
f.write( d, output4="" )
|
|
|
|
assert_equal( output3.strip, output4.strip )
|
|
end
|
|
|
|
def test_ticket_91
|
|
source="<root>
|
|
<bah something='1' somethingelse='bah'>
|
|
<something>great</something>
|
|
</bah>
|
|
</root>"
|
|
expected="<root>
|
|
<bah something='1' somethingelse='bah'>
|
|
<something>great</something>
|
|
</bah>
|
|
<bah/>
|
|
</root>"
|
|
d = Document.new( source )
|
|
d.root.add_element( "bah" )
|
|
p=REXML::Formatters::Pretty.new(2)
|
|
p.compact = true # Don't add whitespace to text nodes unless necessary
|
|
p.write(d,out="")
|
|
assert_equal( expected, out )
|
|
end
|
|
|
|
def test_ticket_95
|
|
testd = REXML::Document.new "<a><b><c/><c/><c/></b></a>"
|
|
testd.write(out1="")
|
|
testd.elements["//c[2]"].xpath
|
|
testd.write(out2="")
|
|
assert_equal(out1,out2)
|
|
end
|
|
|
|
def test_ticket_102
|
|
doc = REXML::Document.new '<doc xmlns="ns"><item name="foo"/></doc>'
|
|
assert_equal( "foo", doc.root.elements["*:item"].attribute("name","ns").to_s )
|
|
assert_equal( "item", doc.root.elements["*:item[@name='foo']"].name )
|
|
end
|
|
|
|
def test_ticket_14
|
|
# Per .2.5 Node Tests of XPath spec
|
|
assert_raise( REXML::UndefinedNamespaceException,
|
|
%Q{Should have gotten an Undefined Namespace error} ) {
|
|
Document.new("<a><n:b/></a>")
|
|
}
|
|
end
|
|
|
|
# 5.7 Text Nodes
|
|
# Character data is grouped into text nodes. As much character data as
|
|
# possible is grouped into each text node: a text node never has an
|
|
# immediately following or preceding sibling that is a text node. The
|
|
# string-value of a text node is the character data. A text node always has
|
|
# at least one character of data.
|
|
def test_ticket_105
|
|
d = Document.new("<a/>")
|
|
d.root.add_text( "a" )
|
|
d.root.add_text( "b" )
|
|
assert_equal( 1, d.root.children.size )
|
|
end
|
|
|
|
# phantom namespace same as default namespace
|
|
def test_ticket_121
|
|
doc = REXML::Document.new(
|
|
'<doc xmlns="ns" xmlns:phantom="ns"><item name="foo">text</item></doc>'
|
|
)
|
|
assert_equal 'text', doc.text( "/*:doc/*:item[@name='foo']" )
|
|
assert_equal "name='foo'",
|
|
doc.root.elements["*:item"].attribute("name", "ns").inspect
|
|
assert_equal "<item name='foo'>text</item>",
|
|
doc.root.elements["*:item[@name='foo']"].to_s
|
|
end
|
|
|
|
def test_ticket_135
|
|
bean_element = REXML::Element.new("bean")
|
|
textToAdd = "(&(|(memberof=CN=somegroupabcdefgh,OU=OUsucks,DC=hookemhorns,DC=com)(mail=*someco.com))(acct=%u)(!(extraparameter:2.2.222.222222.2.2.222:=2)))"
|
|
bean_element.add_element("prop", {"key"=> "filter"}).add_text(textToAdd)
|
|
doc = REXML::Document.new
|
|
doc.add_element(bean_element)
|
|
|
|
REXML::Formatters::Pretty.new(3).write( doc, out = "" )
|
|
|
|
assert_equal "<bean>\n <prop key='filter'>\n (&#38;(|(memberof=CN=somegroupabcdefgh,OU=OUsucks,DC=hookemhorns,DC=com)(mail=*someco.com))(acct=%u)(!(extraparameter:2.2.222.222222.2.2.222:=2)))\n </prop>\n</bean>", out
|
|
end
|
|
|
|
def test_ticket_138
|
|
doc = REXML::Document.new(
|
|
'<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" ' +
|
|
'inkscape:version="0.44" version="1.0"/>'
|
|
)
|
|
expected = {
|
|
"inkscape" => attribute("xmlns:inkscape",
|
|
"http://www.inkscape.org/namespaces/inkscape"),
|
|
"version" => {
|
|
"inkscape" => attribute("inkscape:version", "0.44"),
|
|
"" => attribute("version", "1.0"),
|
|
},
|
|
}
|
|
assert_equal(expected, doc.root.attributes)
|
|
assert_equal(expected, REXML::Document.new(doc.root.to_s).root.attributes)
|
|
end
|
|
|
|
def test_empty_doc
|
|
assert(REXML::Document.new('').children.empty?)
|
|
end
|
|
|
|
private
|
|
def attribute(name, value)
|
|
REXML::Attribute.new(name, value)
|
|
end
|
|
end
|
|
end
|