diff --git a/config/environment.rb b/config/environment.rb index 978f479e..ed1fe107 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,14 @@ +##### # Bootstrap the Rails environment, frameworks, and default configuration +#### + +# Make sure we are using the latest rexml +system_rexml_version = `ruby -r 'rexml/rexml' -e 'p REXML::VERSION'`.split('.').collect {|n| n.to_i} +bundled_rexml_version = `ruby -r 'vendor/plugins/rexml/lib/rexml/rexml' -e 'p REXML::VERSION'`.split('.').collect {|n| n.to_i} +$:.unshift('vendor/plugins/rexml/lib') if (system_rexml_version <=> bundled_rexml_version) == -1 + require File.join(File.dirname(__FILE__), 'boot') + require 'rails_generator/secret_key_generator' Rails::Initializer.run do |config| diff --git a/test/unit/page_renderer_test.rb b/test/unit/page_renderer_test.rb index 91543023..43a63561 100644 --- a/test/unit/page_renderer_test.rb +++ b/test/unit/page_renderer_test.rb @@ -420,7 +420,7 @@ class PageRendererTest < Test::Unit::TestCase def test_textile_image_in_mixed_wiki set_web_property :markup, :mixed assert_markup_parsed_as( - "

\nss

", + "

\nss

", "!http://google.com!\r\nss") end diff --git a/vendor/plugins/maruku/bin/marutest b/vendor/plugins/maruku/bin/marutest index 68e5de69..334f291e 100644 --- a/vendor/plugins/maruku/bin/marutest +++ b/vendor/plugins/maruku/bin/marutest @@ -204,7 +204,18 @@ def run_test(filename, its_ok, verbose=true) }) div = doc.root xml ="" - div.write_children(xml,indent=1,transitive=true,ie_hack=false) + indent=1 + if $rexml_new_version + formatter = if indent > -1 + REXML::Formatters::Pretty.new( indent, ie_hack=false ) + else + REXML::Formatters::Default.new( ie_hack=false ) + end + formatter.write( div, xml) + else + div.write(xml,indent,transitive=true,ie_hack=false) + end + xml.gsub!("\A
(.*)
\Z", "\1") f.write xml rescue Exception=>e f.puts "Error: #{e.inspect}" diff --git a/vendor/plugins/maruku/lib/maruku/output/to_latex_entities.rb b/vendor/plugins/maruku/lib/maruku/output/to_latex_entities.rb index c547f17e..ae314541 100644 --- a/vendor/plugins/maruku/lib/maruku/output/to_latex_entities.rb +++ b/vendor/plugins/maruku/lib/maruku/output/to_latex_entities.rb @@ -215,7 +215,7 @@ module MaRuKu; module Out; module Latex - + @@ -276,7 +276,7 @@ module MaRuKu; module Out; module Latex - + diff --git a/vendor/plugins/maruku/tests/unittest/abbreviations.md b/vendor/plugins/maruku/tests/unittest/abbreviations.md index 55b654a6..5fc4df9b 100644 --- a/vendor/plugins/maruku/tests/unittest/abbreviations.md +++ b/vendor/plugins/maruku/tests/unittest/abbreviations.md @@ -69,4 +69,17 @@ The HTML specification is maintained by the W3C.Operation Tigra Genesis is going

*[Tigra Genesis]:

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ The HTML specification is maintained by the W3C. +

+

+ *[HTML]: Hyper Text Markup Language *[W3C]: World Wide Web Consortium +

+

+ Operation Tigra Genesis is going well. +

+

+ *[Tigra Genesis]: +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/alt.md b/vendor/plugins/maruku/tests/unittest/alt.md index 53b5c3b3..6d9915b2 100644 --- a/vendor/plugins/maruku/tests/unittest/alt.md +++ b/vendor/plugins/maruku/tests/unittest/alt.md @@ -27,4 +27,8 @@ bar

bar

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ bar +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/attributes/att2.md b/vendor/plugins/maruku/tests/unittest/attributes/att2.md index 9b8bc961..6a7432eb 100644 --- a/vendor/plugins/maruku/tests/unittest/attributes/att2.md +++ b/vendor/plugins/maruku/tests/unittest/attributes/att2.md @@ -31,4 +31,8 @@ md_el(:document,[ {:b: a}

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ {a}: a {:b: a} +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/attributes/att3.md b/vendor/plugins/maruku/tests/unittest/attributes/att3.md index 947a4939..6e5e1fa3 100644 --- a/vendor/plugins/maruku/tests/unittest/attributes/att3.md +++ b/vendor/plugins/maruku/tests/unittest/attributes/att3.md @@ -42,4 +42,11 @@ Paragraph1Paragraph2 Paragraph2

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph1 {:#par1} +

+

+ {:#par2} Paragraph2 +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/attributes/attributes.md b/vendor/plugins/maruku/tests/unittest/attributes/attributes.md index 5ccd68fa..75926854 100644 --- a/vendor/plugins/maruku/tests/unittest/attributes/attributes.md +++ b/vendor/plugins/maruku/tests/unittest/attributes/attributes.md @@ -79,4 +79,27 @@ Header with attributesHeader with attributesHeader no attributesParagraph with a

{:hello: .chello}

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Header with attributes {#header1} +

+

+ Header with attributes ### {#header2} +

+

+ Header no attributes +

+

+ {:warn2}Paragraph with a. {#par1} +

+

+ Paragraph with + + emphasis + + {:hello notfound} {#par2} +

+

+ {:hello: .chello} +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/attributes/circular.md b/vendor/plugins/maruku/tests/unittest/attributes/circular.md index 311dfc99..698f2f71 100644 --- a/vendor/plugins/maruku/tests/unittest/attributes/circular.md +++ b/vendor/plugins/maruku/tests/unittest/attributes/circular.md @@ -40,4 +40,11 @@ Paragraph {:b: a}

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph {:a} +

+

+ {:a: b} {:b: a} +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/attributes/default.md b/vendor/plugins/maruku/tests/unittest/attributes/default.md index 36950eaf..4daaddb6 100644 --- a/vendor/plugins/maruku/tests/unittest/attributes/default.md +++ b/vendor/plugins/maruku/tests/unittest/attributes/default.md @@ -35,4 +35,11 @@ Paragraph2

{paragraph}: .maruku-par

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph2 {#2} +

+

+ {paragraph}: .maruku-par +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/blank.md b/vendor/plugins/maruku/tests/unittest/blank.md index 19353125..eddd756a 100644 --- a/vendor/plugins/maruku/tests/unittest/blank.md +++ b/vendor/plugins/maruku/tests/unittest/blank.md @@ -36,4 +36,11 @@ Linea 1Linea 2

Linea 2

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Linea 1 +

+

+ Linea 2 +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/blanks_in_code.md b/vendor/plugins/maruku/tests/unittest/blanks_in_code.md index 79caa022..f35f6916 100644 --- a/vendor/plugins/maruku/tests/unittest/blanks_in_code.md +++ b/vendor/plugins/maruku/tests/unittest/blanks_in_code.md @@ -103,4 +103,29 @@ four *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ This block is composed of three lines: +

+
+  
+   one three 
+  
+ 
+

+ This block is composed of 5 +

+
+  
+   one four 
+  
+ 
+

+ This block is composed of 2 +

+
+  
+   two 
+  
+ 
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/bug_def.md b/vendor/plugins/maruku/tests/unittest/bug_def.md index b46dafa5..0723ae4f 100644 --- a/vendor/plugins/maruku/tests/unittest/bug_def.md +++ b/vendor/plugins/maruku/tests/unittest/bug_def.md @@ -26,4 +26,8 @@ test:

[test][]:

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ [test][]: +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/bug_table.md b/vendor/plugins/maruku/tests/unittest/bug_table.md index c8539494..0db6dfbf 100644 --- a/vendor/plugins/maruku/tests/unittest/bug_table.md +++ b/vendor/plugins/maruku/tests/unittest/bug_table.md @@ -64,4 +64,15 @@ hellohh c1c2

{:t: scope="row"}

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ hello {: summary="Table summary" .class1 style="color:red"} +

+

+ h | h ----------|-- {:t} c1 | c2 {: summary="Table summary" .class1 + style="color:red"} +

+

+ {:t: scope="row"} +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/code.md b/vendor/plugins/maruku/tests/unittest/code.md index 01acbb47..dcbacadb 100644 --- a/vendor/plugins/maruku/tests/unittest/code.md +++ b/vendor/plugins/maruku/tests/unittest/code.md @@ -50,4 +50,13 @@ end tell *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Here is an example of AppleScript: +

+
+  
+   tell application "Foo" beep end tell tab 
+  
+ 
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/code2.md b/vendor/plugins/maruku/tests/unittest/code2.md index dca5b4bf..705895ca 100644 --- a/vendor/plugins/maruku/tests/unittest/code2.md +++ b/vendor/plugins/maruku/tests/unittest/code2.md @@ -43,4 +43,15 @@ Code *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
+

+ Code +

+
+   
+    Ciao 
+   
+  
+
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/code3.md b/vendor/plugins/maruku/tests/unittest/code3.md index c0886a8a..667c19fc 100644 --- a/vendor/plugins/maruku/tests/unittest/code3.md +++ b/vendor/plugins/maruku/tests/unittest/code3.md @@ -99,4 +99,37 @@ This is code (4 spaces):This is not codeThis is code (1 tab):This is not code *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ This is code (4 spaces): +

+
+  
+   Code 
+  
+ 
+

+ This is not code +

+
+  
+   Code 
+  
+ 
+

+ This is code (1 tab): +

+
+  
+   Code 
+  
+ 
+

+ This is not code +

+
+  
+   Code 
+  
+ 
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/data_loss.md b/vendor/plugins/maruku/tests/unittest/data_loss.md index bda289e4..0e976cd2 100644 --- a/vendor/plugins/maruku/tests/unittest/data_loss.md +++ b/vendor/plugins/maruku/tests/unittest/data_loss.md @@ -39,4 +39,10 @@ ijkl *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  1. + abcd efgh ijkl +
  2. +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/easy.md b/vendor/plugins/maruku/tests/unittest/easy.md index f1bbe8d6..461f1afe 100644 --- a/vendor/plugins/maruku/tests/unittest/easy.md +++ b/vendor/plugins/maruku/tests/unittest/easy.md @@ -25,4 +25,15 @@ Hello! how are you?

Hello! how are you?

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ + Hello! + + how are + + you + + ? +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/email.md b/vendor/plugins/maruku/tests/unittest/email.md index ccba8dae..d498eabf 100644 --- a/vendor/plugins/maruku/tests/unittest/email.md +++ b/vendor/plugins/maruku/tests/unittest/email.md @@ -27,7 +27,7 @@ This is an email address: *** Output of Markdown.pl *** -

This is an email address: andrea@invalid.it

+

This is an email address: andrea@invalid.it

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +Error: # diff --git a/vendor/plugins/maruku/tests/unittest/encoding/iso-8859-1.md b/vendor/plugins/maruku/tests/unittest/encoding/iso-8859-1.md index dddbfe87..c9702cde 100644 --- a/vendor/plugins/maruku/tests/unittest/encoding/iso-8859-1.md +++ b/vendor/plugins/maruku/tests/unittest/encoding/iso-8859-1.md @@ -35,4 +35,11 @@ This is iso-8859-1: àèìàù.

This is iso-8859-1: àèìàù.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Encoding: iso-8859-1 +

+

+ This is iso-8859-1: àèìàù. +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/encoding/utf-8.md b/vendor/plugins/maruku/tests/unittest/encoding/utf-8.md index b9a74b9e..5fc95349 100644 --- a/vendor/plugins/maruku/tests/unittest/encoding/utf-8.md +++ b/vendor/plugins/maruku/tests/unittest/encoding/utf-8.md @@ -30,4 +30,11 @@ Japanese: マルク

Japanese: マルク

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Italian: àèìòù. +

+

+ Japanese: マルク +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/entities.md b/vendor/plugins/maruku/tests/unittest/entities.md index 8b6f310a..29b8546b 100644 --- a/vendor/plugins/maruku/tests/unittest/entities.md +++ b/vendor/plugins/maruku/tests/unittest/entities.md @@ -121,4 +121,49 @@ Maruku translates HTML entities to the equivalent in LaTeX:EntityResultabEntity-

It should read just like this: &copy;.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Maruku translates HTML entities to the equivalent in LaTeX: +

+

+ Entity | Result ------------|---------- + + &copy; + + | © + + &pound; + + | £ + + a&nbsp;b + + | a b + + &lambda; + + | λ + + &mdash; + + | — +

+

+ Entity-substitution does not happen in code blocks or inline code. +

+

+ The following should not be translated: +

+
+  
+   &copy; 
+  
+ 
+

+ It should read just like this: + + &copy; + + . +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/escaping.md b/vendor/plugins/maruku/tests/unittest/escaping.md index 3d0d8503..cae9a208 100644 --- a/vendor/plugins/maruku/tests/unittest/escaping.md +++ b/vendor/plugins/maruku/tests/unittest/escaping.md @@ -74,7 +74,7 @@ Hello: ! ! ` { } [ ] ( ) # . ! * * *Ora, emphasis, bold, * <- due asterischi-> * *** Output of Markdown.pl *** -

Hello: ! ! ` { } [ ] ( ) # . ! * * *

+

Hello: ! ! ` { } ( ) # . ! * * *

Ora, emphasis, bold, * <- due asterischi-> * , un underscore-> _ , emphasis, incrediblee!

@@ -86,4 +86,52 @@ Hello: ! ! ` { } [ ] ( ) # . ! * * *Ora, emphasis, bold, * <- due asterischi-> *

End of paragraph

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Hello: ! ! ` { } + + + + + + ( ) # . ! * * * +

+

+ Ora, + + emphasis + + , + + bold + + , * <- due asterischi-> * , un underscore-> _ , + + emphasis + + , incre + + dible + + e! +

+

+ This is + + Code with a special: -> ` <- + + (after) +

+

+ + Start + + of paragraph +

+

+ End of + + paragraph + +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/extra_dl.md b/vendor/plugins/maruku/tests/unittest/extra_dl.md index d964950a..cae5d6fd 100644 --- a/vendor/plugins/maruku/tests/unittest/extra_dl.md +++ b/vendor/plugins/maruku/tests/unittest/extra_dl.md @@ -69,4 +69,14 @@ ApplePomaceous fruit of plants of the genus Malus in the family Rosaceae.OrangeT : The fruit of an evergreen tree of the genus Citrus.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ CSS: style.css +

+

+ Apple : Pomaceous fruit of plants of the genus Malus in the family Rosaceae. +

+

+ Orange : The fruit of an evergreen tree of the genus Citrus. +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/extra_header_id.md b/vendor/plugins/maruku/tests/unittest/extra_header_id.md index fc5edff0..fb78c3f4 100644 --- a/vendor/plugins/maruku/tests/unittest/extra_header_id.md +++ b/vendor/plugins/maruku/tests/unittest/extra_header_id.md @@ -83,4 +83,30 @@ Header 1Header 2Header 3Then you can create links to different parts of the same Link back to header 3

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Header 1 {#header1} +

+

+ Header 2 {#header2} +

+

+ Header 3 ### {#header3} +

+

+ Then you can create links to different parts of the same document like this: +

+

+ + Link back to header 1 + + , + + Link back to header 2 + + , + + Link back to header 3 + +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/extra_table1.md b/vendor/plugins/maruku/tests/unittest/extra_table1.md index 18908068..e705c1c2 100644 --- a/vendor/plugins/maruku/tests/unittest/extra_table1.md +++ b/vendor/plugins/maruku/tests/unittest/extra_table1.md @@ -52,4 +52,12 @@ Content Cell | Content Cell Content Cell | Content Cell

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ CSS: style.css +

+

+ First Header | Second Header ------------- | ------------- Content Cell | + Content Cell Content Cell | Content Cell +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/footnotes.md b/vendor/plugins/maruku/tests/unittest/footnotes.md index 351fdb7e..99f93ae4 100644 --- a/vendor/plugins/maruku/tests/unittest/footnotes.md +++ b/vendor/plugins/maruku/tests/unittest/footnotes.md @@ -123,4 +123,30 @@ This is second sentence (same paragraph).

This is not a footnote.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ That's some text with a footnote [^b] and another [^c] and another [^a]. +

+

+ [^a]: And that's the footnote. +

+
+  
+   That's the second paragraph of the footnote. 
+  
+ 
+

+ [^b]: And that's the footnote. This is second sentence (same paragraph). +

+

+ [^c]: This is the very long one. +

+
+  
+   That's the second paragraph. 
+  
+ 
+

+ This is not a footnote. +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/headers.md b/vendor/plugins/maruku/tests/unittest/headers.md index b18401fc..fe7ecb01 100644 --- a/vendor/plugins/maruku/tests/unittest/headers.md +++ b/vendor/plugins/maruku/tests/unittest/headers.md @@ -51,4 +51,23 @@ A title with emphasisA title with emphasisA title with emphasis

A title with emphasis

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ A title with + + emphasis + +

+

+ A title with + + emphasis + +

+

+ A title with + + emphasis + +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/hex_entities.md b/vendor/plugins/maruku/tests/unittest/hex_entities.md index 20fb77af..6de31f8b 100644 --- a/vendor/plugins/maruku/tests/unittest/hex_entities.md +++ b/vendor/plugins/maruku/tests/unittest/hex_entities.md @@ -47,4 +47,10 @@ Examples of numeric character references include or for the copyright symbol,

Examples of numeric character references include © or © for the copyright symbol, Α or Α for the Greek capital letter alpha, and ا or ا for the Arabic letter alef.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Examples of numeric character references include © or © for the + copyright symbol, Α or Α for the Greek capital letter alpha, and + ا or ا for the Arabic letter alef. +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/hrule.md b/vendor/plugins/maruku/tests/unittest/hrule.md index c3d0dd8a..03e93f82 100644 --- a/vendor/plugins/maruku/tests/unittest/hrule.md +++ b/vendor/plugins/maruku/tests/unittest/hrule.md @@ -57,4 +57,10 @@ md_el(:document,[
*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
+
+
+
+
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/html2.md b/vendor/plugins/maruku/tests/unittest/html2.md index a30498dc..6ec64eac 100644 --- a/vendor/plugins/maruku/tests/unittest/html2.md +++ b/vendor/plugins/maruku/tests/unittest/html2.md @@ -35,4 +35,14 @@ One 123

123

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ One +

+ 123 +

+

+

+ 123 +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/html3.md b/vendor/plugins/maruku/tests/unittest/html3.md index 66bf2648..31dc27be 100644 --- a/vendor/plugins/maruku/tests/unittest/html3.md +++ b/vendor/plugins/maruku/tests/unittest/html3.md @@ -44,4 +44,24 @@ involve coffee, sushi,

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ taking part in + + some arcane conspirations + + which involve + + coffee + + , + + robots + + , + + sushi + + , +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/html4.md b/vendor/plugins/maruku/tests/unittest/html4.md index 4a0552f4..ef9b22d4 100644 --- a/vendor/plugins/maruku/tests/unittest/html4.md +++ b/vendor/plugins/maruku/tests/unittest/html4.md @@ -39,4 +39,10 @@ md_el(:document,[
*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
+ + + +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/html5.md b/vendor/plugins/maruku/tests/unittest/html5.md index 25824c07..4c5df156 100644 --- a/vendor/plugins/maruku/tests/unittest/html5.md +++ b/vendor/plugins/maruku/tests/unittest/html5.md @@ -35,4 +35,12 @@ md_el(:document,[

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+

+ + Aperitif + +
+

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/ie.md b/vendor/plugins/maruku/tests/unittest/ie.md index bb6667a8..5bbd4583 100644 --- a/vendor/plugins/maruku/tests/unittest/ie.md +++ b/vendor/plugins/maruku/tests/unittest/ie.md @@ -79,4 +79,50 @@ md_el(:document,[

{:htmlusesyntax=true lang=xml}

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ + <p>here's an apostrophe & a quote "</p> + +

+
+  
+   <p>here's an apostrophe & a quote "</p> 
+  
+ 
+

+ {:} +

+
+  
+   <p>here's an apostrophe & a quote "</p> 
+  
+ 
+

+ {:lang=xml} +

+
+  
+   <p>here's an apostrophe & a quote "</p> 
+  
+ 
+

+ {:html + + use + + syntax=true lang=not_supported} +

+
+  
+   <p>here's an apostrophe & a quote "</p> 
+  
+ 
+

+ {:html + + use + + syntax=true lang=xml} +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/images.md b/vendor/plugins/maruku/tests/unittest/images.md index 32fa9cf1..afe77911 100644 --- a/vendor/plugins/maruku/tests/unittest/images.md +++ b/vendor/plugins/maruku/tests/unittest/images.md @@ -111,4 +111,28 @@ This page does not uilizes Cascading Style SheetsPlease mouseover to see the tit style="border:0;width:188px;height:131px"

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ This page does not uilizes + Cascading Style Sheets +

+

+ Please mouseover to see the title: + Cascading Style Sheets +

+

+ Please mouseover to see the title: + Cascading Style Sheets +

+

+ I'll say it one more time: this page does not use + Cascading Style Sheets +

+

+ This is double size: ![Cascading Style Sheets] [css2] +

+

+ [css2]: http://jigsaw.w3.org/css-validator/images/vcss "Optional title + attribute" class=external style="border:0;width:188px;height:131px" +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/images2.md b/vendor/plugins/maruku/tests/unittest/images2.md index a9948cf3..a5363342 100644 --- a/vendor/plugins/maruku/tests/unittest/images2.md +++ b/vendor/plugins/maruku/tests/unittest/images2.md @@ -43,4 +43,13 @@ This is an image.This is an image.

This is an ![image].

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ This is an + image + . +

+

+ This is an ![image]. +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/inline_html.md b/vendor/plugins/maruku/tests/unittest/inline_html.md index 6794d6f5..d0101107 100644 --- a/vendor/plugins/maruku/tests/unittest/inline_html.md +++ b/vendor/plugins/maruku/tests/unittest/inline_html.md @@ -238,16 +238,16 @@ Line: Position: Last 80 unconsumed characters:
This is *true* markdown text (paragraph)

-/sw/lib/ruby/1.8/rexml/parsers/baseparser.rb:320:in `pull' -/sw/lib/ruby/1.8/rexml/parsers/treeparser.rb:21:in `parse' -/sw/lib/ruby/1.8/rexml/document.rb:190:in `build' -/sw/lib/ruby/1.8/rexml/document.rb:45:in `initialize' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/parsers/baseparser.rb:320:in `pull' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/parsers/treeparser.rb:21:in `parse' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/document.rb:204:in `build' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/document.rb:42:in `initialize' bin/marutest:200:in `new' bin/marutest:200:in `run_test' -bin/marutest:263:in `marutest' -bin/marutest:260:in `each' -bin/marutest:260:in `marutest' -bin/marutest:335 +bin/marutest:275:in `marutest' +bin/marutest:272:in `each' +bin/marutest:272:in `marutest' +bin/marutest:347 ... Missing end tag for 'img' (got "p") Line: diff --git a/vendor/plugins/maruku/tests/unittest/inline_html2.md b/vendor/plugins/maruku/tests/unittest/inline_html2.md index 4a2ea07e..01c9a9b0 100644 --- a/vendor/plugins/maruku/tests/unittest/inline_html2.md +++ b/vendor/plugins/maruku/tests/unittest/inline_html2.md @@ -33,4 +33,11 @@ md_el(:document,[

Test **bold**

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
+ Test **bold** +
+

+ Test **bold** +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/links.md b/vendor/plugins/maruku/tests/unittest/links.md index e6096aab..10f3f525 100644 --- a/vendor/plugins/maruku/tests/unittest/links.md +++ b/vendor/plugins/maruku/tests/unittest/links.md @@ -162,7 +162,7 @@ Search on GoogleSearch on GoogleSearch on GoogleSearch on GoogleSearch on Google

Inline with title: Google images

-

Search on http://www.gogole.com or http://Here.com or ask bill@google.com +

Search on http://www.gogole.com or http://Here.com or ask bill@google.com or you might ask bill@google.com.

If all else fails, ask Google

@@ -175,16 +175,16 @@ Line: Position: Last 80 unconsumed characters: > -/sw/lib/ruby/1.8/rexml/parsers/baseparser.rb:320:in `pull' -/sw/lib/ruby/1.8/rexml/parsers/treeparser.rb:21:in `parse' -/sw/lib/ruby/1.8/rexml/document.rb:190:in `build' -/sw/lib/ruby/1.8/rexml/document.rb:45:in `initialize' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/parsers/baseparser.rb:320:in `pull' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/parsers/treeparser.rb:21:in `parse' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/document.rb:204:in `build' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/document.rb:42:in `initialize' bin/marutest:200:in `new' bin/marutest:200:in `run_test' -bin/marutest:263:in `marutest' -bin/marutest:260:in `each' -bin/marutest:260:in `marutest' -bin/marutest:335 +bin/marutest:275:in `marutest' +bin/marutest:272:in `each' +bin/marutest:272:in `marutest' +bin/marutest:347 ... Missing end tag for 'p' (got "div") Line: diff --git a/vendor/plugins/maruku/tests/unittest/list1.md b/vendor/plugins/maruku/tests/unittest/list1.md index 8ce272a1..8de39d6b 100644 --- a/vendor/plugins/maruku/tests/unittest/list1.md +++ b/vendor/plugins/maruku/tests/unittest/list1.md @@ -63,4 +63,17 @@ A list item with a blockquote:This is a blockquote inside a list item. *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  • +

    + A list item with a blockquote: +

    +
    +

    + This is a blockquote inside a list item. +

    +
    +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/list2.md b/vendor/plugins/maruku/tests/unittest/list2.md index e66738e1..e863ef44 100644 --- a/vendor/plugins/maruku/tests/unittest/list2.md +++ b/vendor/plugins/maruku/tests/unittest/list2.md @@ -73,4 +73,22 @@ sit amet, consectetuer adipiscing elit.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  • +

    + This is a list item with two paragraphs. +

    +

    + This is the second paragraph in the list item. You're only required to + indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing + elit. +

    +
  • +
  • +

    + other +

    +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/list3.md b/vendor/plugins/maruku/tests/unittest/list3.md index 465b7595..3596fb0e 100644 --- a/vendor/plugins/maruku/tests/unittest/list3.md +++ b/vendor/plugins/maruku/tests/unittest/list3.md @@ -85,4 +85,27 @@ A list item with a blockquote:This is a blockquote inside a list item.A list ite *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  • +

    + A list item with a blockquote: +

    +
    +

    + This is a blockquote inside a list item. +

    +
    +
  • +
  • +

    + A list item with a code block: +

    +
    +    
    +     <code goes here> 
    +    
    +   
    +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/list4.md b/vendor/plugins/maruku/tests/unittest/list4.md index b4336cf6..e733cf41 100644 --- a/vendor/plugins/maruku/tests/unittest/list4.md +++ b/vendor/plugins/maruku/tests/unittest/list4.md @@ -113,4 +113,17 @@ ciao

ciao

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ This is a list: * one * two +

+

+ This is not a list: * one ciao +

+

+ This is a list: 1. one 1. two +

+

+ This is not a list: 1987. one ciao +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists.md b/vendor/plugins/maruku/tests/unittest/lists.md index 28e76e43..8bf57a7d 100644 --- a/vendor/plugins/maruku/tests/unittest/lists.md +++ b/vendor/plugins/maruku/tests/unittest/lists.md @@ -238,4 +238,69 @@ sit amet, consectetuer adipiscing elit.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  • + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit + mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. +
  • +
  • + Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem + consectetuer libero luctus adipiscing. +
  • +
  • + Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem + consectetuer libero luctus adipiscing. +
      +
    • + Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id + sem consectetuer libero luctus adipiscing. +
    • +
    • + Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id + sem consectetuer libero luctus adipiscing. +
    • +
    +
  • +
+

+ Ancora +

+
    +
  • +

    + This is a list item with two paragraphs. Lorem ipsum dolor sit amet, + consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. +

    +

    + ATTENZIONE! +

    +
  • +
  • +

    + Suspendisse id sem consectetuer libero luctus adipiscing. +

    +
  • +
+

+ Ancora +

+
    +
  • +

    + This is a list item with two paragraphs. +

    +

    + This is the second paragraph in the list item. You're only required to + indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing + elit. +

    +
  • +
  • +

    + Another item in the same list. +

    +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists11.md b/vendor/plugins/maruku/tests/unittest/lists11.md index d6692b01..0ae62d25 100644 --- a/vendor/plugins/maruku/tests/unittest/lists11.md +++ b/vendor/plugins/maruku/tests/unittest/lists11.md @@ -28,4 +28,10 @@ md_el(:document,[md_par(["- \316\255\316\275\316\261"])],{},[]) *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  • + ένα +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists6.md b/vendor/plugins/maruku/tests/unittest/lists6.md index 8b0cf1da..268b5d39 100644 --- a/vendor/plugins/maruku/tests/unittest/lists6.md +++ b/vendor/plugins/maruku/tests/unittest/lists6.md @@ -51,4 +51,4 @@ md_el(:document,[],{},[]) *** Output of Markdown.pl (parsed) *** -Error: #:REXML::Element> +
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists7.md b/vendor/plugins/maruku/tests/unittest/lists7.md index 537e6f5f..d9316c52 100644 --- a/vendor/plugins/maruku/tests/unittest/lists7.md +++ b/vendor/plugins/maruku/tests/unittest/lists7.md @@ -76,4 +76,23 @@ CiaoTab * Tab * Tab *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Ciao +

+
    +
  • + Tab +
      +
    • + Tab +
        +
      • + Tab +
      • +
      +
    • +
    +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists7b.md b/vendor/plugins/maruku/tests/unittest/lists7b.md index 4aa09ec4..867b8e90 100644 --- a/vendor/plugins/maruku/tests/unittest/lists7b.md +++ b/vendor/plugins/maruku/tests/unittest/lists7b.md @@ -133,4 +133,21 @@ aa1a2b *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  • + a +
      +
    • + a1 +
    • +
    • + a2 +
    • +
    +
  • +
  • + b +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists8.md b/vendor/plugins/maruku/tests/unittest/lists8.md index 81b1cfd2..0f418fcb 100644 --- a/vendor/plugins/maruku/tests/unittest/lists8.md +++ b/vendor/plugins/maruku/tests/unittest/lists8.md @@ -80,4 +80,19 @@ Here is a paragraph.* Item 1 * Item 2 * Item 3 *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Here is a paragraph. +

+
    +
  • + Item 1 +
  • +
  • + Item 2 +
  • +
  • + Item 3 +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists9.md b/vendor/plugins/maruku/tests/unittest/lists9.md index eb2c487b..b197cd84 100644 --- a/vendor/plugins/maruku/tests/unittest/lists9.md +++ b/vendor/plugins/maruku/tests/unittest/lists9.md @@ -82,4 +82,24 @@ DuetretretreDue *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  • + Due +
      +
    1. + tre +
    2. +
    3. + tre +
    4. +
    5. + tre +
    6. +
    +
  • +
  • + Due +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists_after_paragraph.md b/vendor/plugins/maruku/tests/unittest/lists_after_paragraph.md index 06e3f0cd..91aa9c3d 100644 --- a/vendor/plugins/maruku/tests/unittest/lists_after_paragraph.md +++ b/vendor/plugins/maruku/tests/unittest/lists_after_paragraph.md @@ -265,4 +265,85 @@ Paragraph, list with no space: * ciaoParagraph, list with 1 space: * ciaoParagra

Paragraph with html after, indented: Emphasis tralla Emph

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph, list with no space: * ciao +

+

+ Paragraph, list with 1 space: * ciao +

+

+ Paragraph, list with 3 space: * ciao +

+

+ Paragraph, list with 4 spaces: * ciao +

+

+ Paragraph, list with 1 tab: * ciao +

+

+ Paragraph (1 space after), list with no space: * ciao +

+

+ Paragraph (2 spaces after), list with no space: +
+ * ciao +

+

+ Paragraph (3 spaces after), list with no space: +
+ * ciao +

+

+ Paragraph with block quote: +

+
+

+ Quoted +

+
+

+ Paragraph with header: +

+

+ header +

+

+ Paragraph with header on two lines: +

+

+ header +

+

+ Paragraph with html after +

+
+

+ Paragraph with html after, indented: + + Emphasis + +

+

+ Paragraph with html after, indented: + + Emphasis + + + tralla + + + Emph + +

+

+ Paragraph with html after, indented: + + Emphasis + + tralla + + Emph + +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/lists_ol.md b/vendor/plugins/maruku/tests/unittest/lists_ol.md index 25cc1a0f..bc927dec 100644 --- a/vendor/plugins/maruku/tests/unittest/lists_ol.md +++ b/vendor/plugins/maruku/tests/unittest/lists_ol.md @@ -321,4 +321,93 @@ sit amet, consectetuer adipiscing elit.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+
    +
  1. + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit + mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. +
      +
    1. + Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id + sem consectetuer libero luctus adipiscing. +
    2. +
    +
  2. +
  3. + Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem + consectetuer libero luctus adipiscing. +
      +
    1. + Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id + sem consectetuer libero luctus adipiscing. +
    2. +
    3. + Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id + sem consectetuer libero luctus adipiscing. +
    4. +
    +
  4. +
+

+ Ancora +

+
    +
  1. +

    + This is a list item with two paragraphs. Lorem ipsum dolor sit amet, + consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. +

    +

    + ATTENZIONE! +

    +
      +
    • + Uno +
    • +
    • + Due +
        +
      1. + tre +
      2. +
      3. + tre +
      4. +
      5. + tre +
      6. +
      +
    • +
    • + Due +
    • +
    +
  2. +
  3. +

    + Suspendisse id sem consectetuer libero luctus adipiscing. +

    +
  4. +
+

+ Ancora +

+
    +
  • +

    + This is a list item with two paragraphs. +

    +

    + This is the second paragraph in the list item. You're only required to + indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing + elit. +

    +
  • +
  • +

    + Another item in the same list. +

    +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/loss.md b/vendor/plugins/maruku/tests/unittest/loss.md index 76c40e44..69c5527a 100644 --- a/vendor/plugins/maruku/tests/unittest/loss.md +++ b/vendor/plugins/maruku/tests/unittest/loss.md @@ -26,4 +26,9 @@ md_el(:document,[md_html("
")],{},[])


123

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+
+ 123 +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/math/equations.md b/vendor/plugins/maruku/tests/unittest/math/equations.md index 0091932d..2425fb65 100644 --- a/vendor/plugins/maruku/tests/unittest/math/equations.md +++ b/vendor/plugins/maruku/tests/unittest/math/equations.md @@ -54,16 +54,58 @@ $$ x = y $$$$ x$$ x = y $$$$ x = y $$ *** Output of Markdown.pl *** -

$$ x = y $$

+x=y -

$$ x -= y $$

+x=y -

$$ -x = y $$

+x=y -

$$ x = y -$$

+x=y *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+ + + x + + + = + + + y + + + + + x + + + = + + + y + + + + + x + + + = + + + y + + + + + x + + + = + + + y + + +
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/math/inline.md b/vendor/plugins/maruku/tests/unittest/math/inline.md index 2c393d05..f0c97be8 100644 --- a/vendor/plugins/maruku/tests/unittest/math/inline.md +++ b/vendor/plugins/maruku/tests/unittest/math/inline.md @@ -91,11 +91,61 @@ Here are some formulas:Thats it, nothing else is supported.

Here are some formulas:

    -
  • $\alpha$
  • -
  • $x^{n}+y^{n} \neq z^{n}$
  • +
  • α
  • +
  • x n+y nz n

That's it, nothing else is supported.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Here are some formulas: +

+
    +
  • + + + α + + +
  • +
  • + + + + x + + + n + + + + + + + + + y + + + n + + + + ≠ + + + + z + + + n + + + +
  • +
+

+ That's it, nothing else is supported. +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/math/math2.md b/vendor/plugins/maruku/tests/unittest/math/math2.md index b82dc731..9280fdd8 100644 --- a/vendor/plugins/maruku/tests/unittest/math/math2.md +++ b/vendor/plugins/maruku/tests/unittest/math/math2.md @@ -57,9 +57,7 @@ md_el(:document,[ *** Output of Markdown.pl *** -

[ - \alpha -]

+α

\begin{equation} \alpha @@ -71,4 +69,19 @@ md_el(:document,[

\begin{equation} \gamma \end{equation}

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+ + + α + + +

+ \begin{equation} \alpha \end{equation} +

+

+ \begin{equation} \beta \end{equation} +

+

+ \begin{equation} \gamma \end{equation} +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/math/notmath.md b/vendor/plugins/maruku/tests/unittest/math/notmath.md index c69c429f..54f4c11e 100644 --- a/vendor/plugins/maruku/tests/unittest/math/notmath.md +++ b/vendor/plugins/maruku/tests/unittest/math/notmath.md @@ -32,9 +32,24 @@ This is not $math$.[ \alpha ] *** Output of Markdown.pl *** -

This is not $math$.

+

This is not math.

-

[ \alpha ]

+α *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ This is not + + + math + + + . +

+ + + α + + +
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/math/table.md b/vendor/plugins/maruku/tests/unittest/math/table.md index 92645a3f..ac463e46 100644 --- a/vendor/plugins/maruku/tests/unittest/math/table.md +++ b/vendor/plugins/maruku/tests/unittest/math/table.md @@ -48,11 +48,28 @@ md_el(:document,[ *** Output of Markdown.pl *** - $\alpha$ + α - +
$\beta$β
*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+ + + + α + + + + + +
+ + + β + + +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/math/table2.md b/vendor/plugins/maruku/tests/unittest/math/table2.md index 0f513c32..18e3e4ae 100644 --- a/vendor/plugins/maruku/tests/unittest/math/table2.md +++ b/vendor/plugins/maruku/tests/unittest/math/table2.md @@ -57,4 +57,12 @@ SymbolMeaningcomments The firstI like it. The firstI like it.

{:r: scope='row'}

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Symbol | Meaning | comments ------------|---------|--------- {:r} α | + The first | I like it. {:r} ℵ | The first | I like it. +

+

+ {:r: scope='row'} +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/misc_sw.md b/vendor/plugins/maruku/tests/unittest/misc_sw.md index c9ffe938..159ee8e9 100644 --- a/vendor/plugins/maruku/tests/unittest/misc_sw.md +++ b/vendor/plugins/maruku/tests/unittest/misc_sw.md @@ -612,4 +612,326 @@ the alternative is PowerPoint with the Tex *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Subject: Software not painful to use Subject_short: painless software Topic: + /misc/coolsw Archive: no Date: Nov 20 2006 Order: -9.5 inMenu: true +

+

+ General +

+
+

+ Development +

+
    +
  • + + Build system + + : + + cmake + + , throw the + + autotools + + away. +
  • +
  • + + Source code control system + + : ditch CVS for + + subversion + + . +
  • +
  • + + Project management + + : + + Trac + + tracks everything. +
  • +
  • +

    + + Scripting language + + : + + Ruby + + is Japanese pragmatism (and has a + + poignant + + guide). Python, you say? Python is too academic and snob: +

    +

    + $ python +
    + Python 2.4.1 (#1, Jun 4 2005, 00:54:33) Type "help", "copyright", "credits" + or "license" for more information. +

    +
    +
    +
    +

    + exit 'Use Ctrl-D (i.e. EOF) to exit.' quit 'Use Ctrl-D (i.e. EOF) to + exit.' +

    +
    +
    +
    +
  • +
  • +

    + + Java IDE + + : + + JBuilder + + is great software and has a free version (IMHO better than Eclipse). Java + is not a pain anymore since it gained + + generics + + and got opensourced. +

    +
  • +
  • + + Mark-up language + + : HTML is so 2001, why don't you take at look at + + Markdown + + ? + + Look at the source of this page + + . +
  • +
  • + + C++ libraries + + : + +
  • +
+

+ Research +

+ +

+ Cool websites +

+ +
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/notyet/escape.md b/vendor/plugins/maruku/tests/unittest/notyet/escape.md index 98afb61e..058211b7 100644 --- a/vendor/plugins/maruku/tests/unittest/notyet/escape.md +++ b/vendor/plugins/maruku/tests/unittest/notyet/escape.md @@ -33,4 +33,15 @@ md_el(:document,[md_par([md_code("\\\\")]), md_par([md_code("\\")])],{},[])

\

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ + \\ + +

+

+ + \ + +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/notyet/header_after_par.md b/vendor/plugins/maruku/tests/unittest/notyet/header_after_par.md index f335b526..d7affc26 100644 --- a/vendor/plugins/maruku/tests/unittest/notyet/header_after_par.md +++ b/vendor/plugins/maruku/tests/unittest/notyet/header_after_par.md @@ -78,4 +78,23 @@ ParagraphheaderParagraphheaderParagraphheader

header

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph +

+

+ header +

+

+ Paragraph +

+

+ header +

+

+ Paragraph +

+

+ header +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/notyet/ticks.md b/vendor/plugins/maruku/tests/unittest/notyet/ticks.md index cb081bd0..515cfb56 100644 --- a/vendor/plugins/maruku/tests/unittest/notyet/ticks.md +++ b/vendor/plugins/maruku/tests/unittest/notyet/ticks.md @@ -28,4 +28,10 @@ md_el(:document,[md_par([md_code("There is a literal backtick (`) here.")])],{},

There is a literal backtick (`) here.

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ + There is a literal backtick (`) here. + +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/notyet/triggering.md b/vendor/plugins/maruku/tests/unittest/notyet/triggering.md index 8a102c95..d0acc4ae 100644 --- a/vendor/plugins/maruku/tests/unittest/notyet/triggering.md +++ b/vendor/plugins/maruku/tests/unittest/notyet/triggering.md @@ -203,4 +203,53 @@ Paragraph, list with no space: * ciaoParagraph, list with 1 space: * ciaoParagra

header

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph, list with no space: * ciao +

+

+ Paragraph, list with 1 space: * ciao +

+

+ Paragraph, list with 3 space: * ciao +

+

+ Paragraph, list with 4 spaces: * ciao +

+

+ Paragraph, list with 1 tab: * ciao +

+

+ Paragraph (1 space after), list with no space: * ciao +

+

+ Paragraph (2 spaces after), list with no space: +
+ * ciao +

+

+ Paragraph (3 spaces after), list with no space: +
+ * ciao +

+

+ Paragraph with block quote: +

+
+

+ Quoted +

+
+

+ Paragraph with header: +

+

+ header +

+

+ Paragraph with header on two lines: +

+

+ header +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/olist.md b/vendor/plugins/maruku/tests/unittest/olist.md index b4fa979b..43f939ce 100644 --- a/vendor/plugins/maruku/tests/unittest/olist.md +++ b/vendor/plugins/maruku/tests/unittest/olist.md @@ -61,4 +61,19 @@ This is a list:onetwothree *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ This is a list: +

+
    +
  1. + one +
  2. +
  3. + two +
  4. +
  5. + three +
  6. +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/one.md b/vendor/plugins/maruku/tests/unittest/one.md index c8af09fc..4b62db34 100644 --- a/vendor/plugins/maruku/tests/unittest/one.md +++ b/vendor/plugins/maruku/tests/unittest/one.md @@ -25,4 +25,8 @@ One line

One line

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ One line +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/paragraph.md b/vendor/plugins/maruku/tests/unittest/paragraph.md index ce1279e5..01e500d3 100644 --- a/vendor/plugins/maruku/tests/unittest/paragraph.md +++ b/vendor/plugins/maruku/tests/unittest/paragraph.md @@ -26,4 +26,8 @@ Paragraph

Paragraph

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/paragraph_rules/dont_merge_ref.md b/vendor/plugins/maruku/tests/unittest/paragraph_rules/dont_merge_ref.md index b2d35296..348acb31 100644 --- a/vendor/plugins/maruku/tests/unittest/paragraph_rules/dont_merge_ref.md +++ b/vendor/plugins/maruku/tests/unittest/paragraph_rules/dont_merge_ref.md @@ -54,4 +54,8 @@ Paragraph Paragraph

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph Paragraph Paragraph +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/paragraph_rules/tab_is_blank.md b/vendor/plugins/maruku/tests/unittest/paragraph_rules/tab_is_blank.md index 29d6100d..fc3869b5 100644 --- a/vendor/plugins/maruku/tests/unittest/paragraph_rules/tab_is_blank.md +++ b/vendor/plugins/maruku/tests/unittest/paragraph_rules/tab_is_blank.md @@ -36,4 +36,11 @@ Paragraph1Paragraph2

Paragraph2

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph1 +

+

+ Paragraph2 +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/paragraphs.md b/vendor/plugins/maruku/tests/unittest/paragraphs.md index 45b07be4..7357182b 100644 --- a/vendor/plugins/maruku/tests/unittest/paragraphs.md +++ b/vendor/plugins/maruku/tests/unittest/paragraphs.md @@ -63,4 +63,16 @@ Paragraph Br->
Paragraph 5

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Paragraph 1 +

+

+ Paragraph 2 +

+

+ Paragraph 3 Paragraph 4 Paragraph Br-> +
+ Paragraph 5 +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/recover/recover_links.md b/vendor/plugins/maruku/tests/unittest/recover/recover_links.md index 5f6e374e..b1445f55 100644 --- a/vendor/plugins/maruku/tests/unittest/recover/recover_links.md +++ b/vendor/plugins/maruku/tests/unittest/recover/recover_links.md @@ -25,4 +25,8 @@ Search on Google imagesGoOgle search ]

Search on [Google images][ GoOgle search ]

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Search on [Google images][ GoOgle search ] +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/references/long_example.md b/vendor/plugins/maruku/tests/unittest/references/long_example.md index 81a50d84..fcf57570 100644 --- a/vendor/plugins/maruku/tests/unittest/references/long_example.md +++ b/vendor/plugins/maruku/tests/unittest/references/long_example.md @@ -85,4 +85,36 @@ inspiration for Markdown's syntax is the format of plain text email.

To this end, Markdown's syntax is comprised entirely of punctuation

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ filters -- including + + Setext + + , + + atx + + , + + Textile + + , + + reStructuredText + + , + + Grutatext + + , and + + EtText + + -- the single biggest source of inspiration for Markdown's syntax is the + format of plain text email. +

+

+ To this end, Markdown's syntax is comprised entirely of punctuation +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/references/spaces_and_numbers.md b/vendor/plugins/maruku/tests/unittest/references/spaces_and_numbers.md index 5d40e8ac..5549e977 100644 --- a/vendor/plugins/maruku/tests/unittest/references/spaces_and_numbers.md +++ b/vendor/plugins/maruku/tests/unittest/references/spaces_and_numbers.md @@ -25,4 +25,4 @@ md_el(:document,[md_ref_def("6", "http://ettext.taint.org/doc/", {:title=>nil})] *** Output of Markdown.pl (parsed) *** -Error: #:REXML::Element> +
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/smartypants.md b/vendor/plugins/maruku/tests/unittest/smartypants.md index 938c4ff4..91949234 100644 --- a/vendor/plugins/maruku/tests/unittest/smartypants.md +++ b/vendor/plugins/maruku/tests/unittest/smartypants.md @@ -149,16 +149,16 @@ Line: Position: Last 80 unconsumed characters:
She was 6\"12\'. 

She was 6\"12\'. -/sw/lib/ruby/1.8/rexml/parsers/baseparser.rb:320:in `pull' -/sw/lib/ruby/1.8/rexml/parsers/treeparser.rb:21:in `parse' -/sw/lib/ruby/1.8/rexml/document.rb:190:in `build' -/sw/lib/ruby/1.8/rexml/document.rb:45:in `initialize' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/parsers/baseparser.rb:320:in `pull' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/parsers/treeparser.rb:21:in `parse' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/document.rb:204:in `build' +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rexml/document.rb:42:in `initialize' bin/marutest:200:in `new' bin/marutest:200:in `run_test' -bin/marutest:263:in `marutest' -bin/marutest:260:in `each' -bin/marutest:260:in `marutest' -bin/marutest:335 +bin/marutest:275:in `marutest' +bin/marutest:272:in `each' +bin/marutest:272:in `marutest' +bin/marutest:347 ... Missing end tag for 'here' (got "p") Line: diff --git a/vendor/plugins/maruku/tests/unittest/syntax_hl.md b/vendor/plugins/maruku/tests/unittest/syntax_hl.md index 7cdd5b33..51ab1292 100644 --- a/vendor/plugins/maruku/tests/unittest/syntax_hl.md +++ b/vendor/plugins/maruku/tests/unittest/syntax_hl.md @@ -63,18 +63,8 @@ This is ruby code:This is ruby code:

require 'maruku'
 
-puts Maruku.new($stdin).to_html
-
- -

This is ruby code:

- -
require 'maruku'
-
- -

{: lang=ruby htmlusesyntax}

- -
puts Maruku.new($stdin).to_html
+puts Maruku.new(<math xmlns='http://www.w3.org/1998/Math/MathML' display='inline'><mi>stdin</mi><mo stretchy="false">)</mo><mo>.</mo><msub><mi>to</mi> <mi>html</mi></msub><mi>This</mi><mi>is</mi><mi>ruby</mi><mi>code</mi><mo>:</mo><mi>require</mi><mo>&prime;</mo><mi>maruku</mi><mo>&prime;</mo><mrow><mo>:</mo><mi>lang</mi><mo>=</mo><mi>ruby</mi><msub><mi>html</mi> <mi>use</mi></msub><msub><mo></mo><mi>syntax</mi></msub></mrow><mi>puts</mi><mi>Maruku</mi><mo>.</mo><mi>new</mi><mo stretchy="false">(</mo></math>stdin).to_html
 
*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +Error: # diff --git a/vendor/plugins/maruku/tests/unittest/table_attributes.md b/vendor/plugins/maruku/tests/unittest/table_attributes.md index 82d4988a..d9c8dc7f 100644 --- a/vendor/plugins/maruku/tests/unittest/table_attributes.md +++ b/vendor/plugins/maruku/tests/unittest/table_attributes.md @@ -49,4 +49,13 @@ hh c1c2

{:t: scope="row"}

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ h | h ----------|-- {:t} c1 | c2 {: summary="Table summary" .class1 + style="color:red" border=3 width="50%" frame=lhs rules=cols cellspacing=2em + cellpadding=4px} +

+

+ {:t: scope="row"} +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/test.md b/vendor/plugins/maruku/tests/unittest/test.md index 8b9be20a..d8eea239 100644 --- a/vendor/plugins/maruku/tests/unittest/test.md +++ b/vendor/plugins/maruku/tests/unittest/test.md @@ -29,4 +29,8 @@ md_el(:document,[md_el(:code,[],{:raw_code=>" $ python "},[])],{},[]

$ python

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ $ python +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/wrapping.md b/vendor/plugins/maruku/tests/unittest/wrapping.md index 453b90d6..4cb64de7 100644 --- a/vendor/plugins/maruku/tests/unittest/wrapping.md +++ b/vendor/plugins/maruku/tests/unittest/wrapping.md @@ -85,4 +85,25 @@ Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem + ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum + dolor amet. Break: +
+ Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem + ipsum dolor amet. +

+
    +
  • + Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem + ipsum dolor amet Lorem ipsum Break: +
    + Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet +
  • +
  • + Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem + ipsum dolor amet +
  • +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/xml.md b/vendor/plugins/maruku/tests/unittest/xml.md index 57772eef..598df0a8 100644 --- a/vendor/plugins/maruku/tests/unittest/xml.md +++ b/vendor/plugins/maruku/tests/unittest/xml.md @@ -51,4 +51,16 @@ width="600px" height="400px">

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ +

+

+ + + + + + +

+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/xml2.md b/vendor/plugins/maruku/tests/unittest/xml2.md index 946a18ca..a2c25b97 100644 --- a/vendor/plugins/maruku/tests/unittest/xml2.md +++ b/vendor/plugins/maruku/tests/unittest/xml2.md @@ -31,4 +31,8 @@ md_el(:document,[md_html("")],{},[]) --> *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+ +
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/xml3.md b/vendor/plugins/maruku/tests/unittest/xml3.md index 65d725e7..4ded6cba 100644 --- a/vendor/plugins/maruku/tests/unittest/xml3.md +++ b/vendor/plugins/maruku/tests/unittest/xml3.md @@ -41,4 +41,13 @@ md_el(:document,[ *** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+ + Blah + + + +
+ *em* +
+
\ No newline at end of file diff --git a/vendor/plugins/maruku/tests/unittest/xml_instruction.md b/vendor/plugins/maruku/tests/unittest/xml_instruction.md index 3149b3f3..2bbff43d 100644 --- a/vendor/plugins/maruku/tests/unittest/xml_instruction.md +++ b/vendor/plugins/maruku/tests/unittest/xml_instruction.md @@ -69,4 +69,23 @@ Targets Inside: last

Inside: last

*** Output of Markdown.pl (parsed) *** -Error: # ... :REXML::Element> +
+

+ + + + +

+

+ Targets + + + + +

+

+ Inside: + + last +

+
\ No newline at end of file diff --git a/vendor/plugins/rexml/lib/require_with_version.rb b/vendor/plugins/rexml/lib/require_with_version.rb new file mode 100644 index 00000000..ccd9ff90 --- /dev/null +++ b/vendor/plugins/rexml/lib/require_with_version.rb @@ -0,0 +1,167 @@ +# FUNDAMENTAL FLAWS: +# The order of $: must be preserved. Therefore, there are two sort +# criteria: Versioned files are sorted high; after that, the sort order +# is the order of $:. +# We must preserve the load path; if rexml-2.4 is required in one place, +# all rexml/* packages should be loaded from there. +############################################################################ +# # +# This is based on Phil Tomson's # +# ("ptkwt!shell1#aracnet#com".tr("!#","@.")) # +# code. The changes I made are: # +# 1) The Version class is now a member of the Kernel module, to avoid # +# name space conflicts. # +# 2) Version::to_s() returns the original string, not a comma-separated # +# string. # +# 3) The versioning is package based, not file based. In fact, with # +# this, you can't version individual files. AFAIC, this is better, # +# since versioning on individual files is much more tedious than # +# package-based versioning, and it is arguably less useful and less # +# commonly desired. # +# 4) Versions can have arbitrary length. EG: 2.7 < 2.7.1, and "2" # +# matches any version that starts with "2", such as "2.5.2.6.7" # +# # +# The rules are these: # +# 1) All of the locations in $: will be searched # +# 2) The highest version of the package found that satisfies the # +# requirements will be used. # +# 3) If there is no versioned package, or no version matches, we default # +# to the normal Ruby require mechanism. This maintains backward # +# compatible behavior. # +# 4) The packages must be installed as foo-x.y.z. The cardinality of # +# the version is not significant, and packages that do not match this # +# naming pattern match by default. # +# # +# Rule (1) and (2) mean that the highest matching version anywhere in # +# the search path will be used. Rule (3) and (4) mean that even if # +# packages are not installed with this naming convention, programs that # +# use require_version will still work. # +# # +# Usage: # +# To use this, require this module. Then use require_with_ver, instead # +# of require in your files. # +# # +# Examples: # +# require_version('rexml/document'){|v| v > '2.0' and v < '2.5'} # +# require_version('rexml/document'){|v| v > '2.0'} # +# require_version('rexml/document') # +# require_version('rexml/document'){|v| v > '2.0'} # +# require_version('rexml/document'){|v| v >= '1.0' and v < '2.0'} # +# require_version('rexml/document'){|v| v >= '1.0' and v < '2.0' and # +# v != '1.7'} # +# require_version('rexml/document'){|v| (v >= '1.0' and # +# v < '2.0' and # +# v != '1.7') or # +# v == '3.0.1'} # +# require_version('rexml/document'){|v| v.to_s =~ /^2.[02468]/} # +# # +############################################################################ + +module Kernel + ######################################################### + # Version - takes a string in the form: 'X1.X2.X3...Xn' # + # (where 'Xn' is a number) # + ######################################################### + class Version + include Comparable + def initialize(str) + @vs = str.split('.').map!{|i| i.to_i} + end + + def [](i) + @vs[i] + end + + def to_s + @vs.join('.') + end + + def <=>(other) + if other.class == String + other = Version.new(other) + end + @vs.each_with_index { |v,i| + return 1 unless other[i] + unless v == other[i] + return v <=> other[i] + end + } + return 0 + end + end + + alias :old_require :require + + @@__versioned__ = {} + def require(file,&b) + path = file.split('/') + root = path[0] + rest = path[1..-1].join('/') + unless @@__versioned__[root] + package = File.dirname( file ) + files = [] + $:.each {|dir| + if File.exists? dir + fileset = Dir.new(dir).entries.delete_if {|f| + fpath = File.join( dir, f ) + !(File.directory?(fpath) and f =~ /^#{root}(-\d(\.\d)*)?$/) + } + fileset.collect!{ |f| File.join( dir, f ) } + files += fileset + end + } + if files.size > 0 + @@__versioned__[root] = files.uniq.sort{|x,y| + File.basename(x) <=> File.basename(y) + } + @@__versioned__[root].reverse! + else + @@__versioned__[root] = [root] + end + end + base = @@__versioned__[root][0] + if b #block_given? + p @@__versioned__[root] + base = @@__versioned__[root].delete_if { |f| + l = File.basename(f) + l.include?('-') and yield( Version.new( l.split('-')[1] ) ) and + Dir.new(f).entries.include?( rest+".rb" ) ? false : true + } + p base + base = base[0] + end + #old_require "#{base}/#{rest}" + puts <<-EOL + old_require "#{base}/#{rest}" + EOL + end +end + +#=begin +# For testing +if $0 == __FILE__ + $: << "./" + puts "\n\nv > '2.0' and v < '2.5'" + require('rexml/document'){|v| v > '2.0' and v < '2.5'} + puts "\n\nv > '2.0' and v < '3'" + require('rexml/document'){|v| v > '2.0' and v < '3'} +=begin + puts "\n\nv > '2.0'" + require('rexml/document'){|v| v > '2.0'} + require('rexml/document') + puts "\n\nv > '2.0'" + require('rexml/document'){|v| v > '2.0'} + puts "\n\nv >= '1.0' and v < '2.0'" + require('rexml/document'){|v| v >= '1.0' and v < '2.0'} + puts "\n\nv >= '1.0' and v < '2.0' and v != '1.7'" + require('rexml/document'){|v| v >= '1.0' and v < '2.0' and v != '1.7'} + require('rexml/document'){|v| (v >= '1.0' and + v < '2.0' and + v != '1.7') or + v == '3.0.1'} + puts "\n\nv.to_s =~ /^2.[02468]/" + require('rexml/document'){|v| v.to_s =~ /^2.[02468]/} + require('rexml/parsers/baseparser' ) +=end +end +#=end diff --git a/vendor/plugins/rexml/lib/rexml/attlistdecl.rb b/vendor/plugins/rexml/lib/rexml/attlistdecl.rb new file mode 100644 index 00000000..d4b5c38a --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/attlistdecl.rb @@ -0,0 +1,62 @@ +#vim:ts=2 sw=2 noexpandtab: +require 'rexml/child' +require 'rexml/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 forseeable 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 + + # Itterate 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 diff --git a/vendor/plugins/rexml/lib/rexml/attribute.rb b/vendor/plugins/rexml/lib/rexml/attribute.rb new file mode 100644 index 00000000..17ced44c --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/attribute.rb @@ -0,0 +1,188 @@ +require "rexml/namespace" +require 'rexml/text' + +module REXML + # Defines an Element Attribute; IE, a attribute=value pair, as in: + # . 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 # -> "elns" + # a = Attribute.new( "x", "y" ) + # a.prefix # -> "" + def prefix + pf = super + if pf == "" + pf = @element.prefix if @element + end + pf + end + + # Returns the namespace URL, if defined, or nil otherwise + # + # e = Element.new("el") + # e.add_attributes({"xmlns:ns", "http://url"}) + # e.namespace( "ns" ) # -> "http://url" + def namespace arg=nil + arg = prefix if arg.nil? + @element.namespace arg + 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(/"/, '"e;')}"^ + else + "#@expanded_name='#{to_s().gsub(/'/, ''')}'" + end + end + + def doctype + if @element + doc = @element.document + doctype = 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 successfull + # + # 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: diff --git a/vendor/plugins/rexml/lib/rexml/cdata.rb b/vendor/plugins/rexml/lib/rexml/cdata.rb new file mode 100644 index 00000000..856b9ef8 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/cdata.rb @@ -0,0 +1,67 @@ +require "rexml/text" + +module REXML + class CData < Text + START = '' + ILLEGAL = /(\]\]>)/ + + # Constructor. CData is data between + # + # _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 ) #-> + def write( output=$stdout, indent=-1, transitive=false, ie_hack=false ) + Kernel.warn( "#{self.class.name}.write is deprecated" ) + indent( output, indent ) + output << START + output << @string + output << STOP + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/child.rb b/vendor/plugins/rexml/lib/rexml/child.rb new file mode 100644 index 00000000..6d3c9df5 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/child.rb @@ -0,0 +1,96 @@ +require "rexml/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 + # # => + 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 + # # => + 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 + encoding = document.encoding + + to_s + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/comment.rb b/vendor/plugins/rexml/lib/rexml/comment.rb new file mode 100644 index 00000000..2b9b4b89 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/comment.rb @@ -0,0 +1,80 @@ +require "rexml/child" + +module REXML + ## + # Represents an XML comment; that is, text between \ + class Comment < Child + include Comparable + START = "" + + # 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 ) + #puts "IN COMMENT CONSTRUCTOR; SECOND IS #{second.type}" + 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") + 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: diff --git a/vendor/plugins/rexml/lib/rexml/doctype.rb b/vendor/plugins/rexml/lib/rexml/doctype.rb new file mode 100644 index 00000000..e90c12d5 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/doctype.rb @@ -0,0 +1,270 @@ +require "rexml/parent" +require "rexml/parseexception" +require "rexml/namespace" +require 'rexml/entity' +require 'rexml/attlistdecl' +require 'rexml/xmltokens' + +module REXML + # Represents an XML DOCTYPE declaration; that is, the contents of . 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 = "" + 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' ) + # # + # dt = DocType.new( doctype_to_clone ) + # # Incomplete. Shallow clone of doctype + # + # +Note+ that the constructor: + # + # Doctype.new( Source.new( "" ) ) + # + # 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 + indent( output, indent ) + output << START + output << ' ' + output << @name + output << " #@external_id" if @external_id + output << " #{@long_name.inspect}" if @long_name + output << " #{@uri.inspect}" if @uri + unless @children.empty? + next_indent = indent + 1 + output << ' [' + @children.each { |child| + output << "\n" + f.write( child, output ) + } + output << "\n]" + end + output << STOP + end + + def context + @parent.context + 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 + "" + 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 diff --git a/vendor/plugins/rexml/lib/rexml/document.rb b/vendor/plugins/rexml/lib/rexml/document.rb new file mode 100644 index 00000000..f09aa2bc --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/document.rb @@ -0,0 +1,208 @@ +require "rexml/element" +require "rexml/xmldecl" +require "rexml/source" +require "rexml/comment" +require "rexml/doctype" +require "rexml/instruction" +require "rexml/rexml" +require "rexml/parseexception" +require "rexml/output" +require "rexml/parsers/baseparser" +require "rexml/parsers/streamparser" +require "rexml/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 = {} ) + 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 + @children.unshift child + 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 = 0 + @children.find { |x| + insert_before_index += 1 + x.kind_of?(Element) || x.kind_of?(DocType) + } + if @children[ insert_before_index ] # Not null = not end of list + if @children[ insert_before_index ].kind_of DocType + @children[ insert_before_index ] = child + else + @children[ index_before_index-1, 0 ] = child + end + else # Insert at end of list + @children[insert_before_index] = 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 + rv = @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 a String. + # 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 + + # 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 () 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 unneccessary bandwidth to applications such + # as XML-RPC. + # + # See also the classes in the rexml/formatters package for the proper way + # to change the default formatting of XML output + # + # _Examples_ + # Document.new("").serialize + # + # output_string = "" + # tr = Transitive.new( output_string ) + # Document.new("").serialize( tr ) + # + # 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 + # trans:: + # 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:: + # Internet Explorer is the worst piece of crap to have ever been + # written, with the possible exception of Windows itself. Since IE is + # unable to parse proper XML, we have to provide a hack to generate XML + # that IE's limited abilities can handle. This hack inserts a space + # before the /> on empty tags. Defaults to false + def write( output=$stdout, indent=-1, transitive=false, ie_hack=false ) + if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output) + output = Output.new( output, xml_decl.encoding ) + end + formatter = if indent > -1 + if trans + 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 + + private + def build( source ) + Parsers::TreeParser.new( source, self ).parse + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/dtd/attlistdecl.rb b/vendor/plugins/rexml/lib/rexml/dtd/attlistdecl.rb new file mode 100644 index 00000000..e176bb07 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/dtd/attlistdecl.rb @@ -0,0 +1,10 @@ +require "rexml/child" +module REXML + module DTD + class AttlistDecl < Child + START = ")/um + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/dtd/dtd.rb b/vendor/plugins/rexml/lib/rexml/dtd/dtd.rb new file mode 100644 index 00000000..4f735d48 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/dtd/dtd.rb @@ -0,0 +1,51 @@ +require "rexml/dtd/elementdecl" +require "rexml/dtd/entitydecl" +require "rexml/comment" +require "rexml/dtd/notationdecl" +require "rexml/dtd/attlistdecl" +require "rexml/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 = $& + source = $' + contents << ElementDecl.new( match ) + when AttlistDecl.PATTERN_RE + matchdata = $~ + source = $' + contents << AttlistDecl.new( matchdata ) + when EntityDecl.PATTERN_RE + matchdata = $~ + source = $' + contents << EntityDecl.new( matchdata ) + when Comment.PATTERN_RE + matchdata = $~ + source = $' + contents << Comment.new( matchdata ) + when NotationDecl.PATTERN_RE + matchdata = $~ + source = $' + contents << NotationDecl.new( matchdata ) + end + end + contents + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/dtd/elementdecl.rb b/vendor/plugins/rexml/lib/rexml/dtd/elementdecl.rb new file mode 100644 index 00000000..c4e620f3 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/dtd/elementdecl.rb @@ -0,0 +1,17 @@ +require "rexml/child" +module REXML + module DTD + class ElementDecl < Child + 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 diff --git a/vendor/plugins/rexml/lib/rexml/dtd/entitydecl.rb b/vendor/plugins/rexml/lib/rexml/dtd/entitydecl.rb new file mode 100644 index 00000000..a5f1520f --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/dtd/entitydecl.rb @@ -0,0 +1,56 @@ +require "rexml/child" +module REXML + module DTD + class EntityDecl < Child + START = "/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 + # + # + 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 = " 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 diff --git a/vendor/plugins/rexml/lib/rexml/dtd/notationdecl.rb b/vendor/plugins/rexml/lib/rexml/dtd/notationdecl.rb new file mode 100644 index 00000000..a47ff8f2 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/dtd/notationdecl.rb @@ -0,0 +1,39 @@ +require "rexml/child" +module REXML + module DTD + class NotationDecl < Child + START = "/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 + "" + 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 diff --git a/vendor/plugins/rexml/lib/rexml/element.rb b/vendor/plugins/rexml/lib/rexml/element.rb new file mode 100644 index 00000000..925bdd4e --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/element.rb @@ -0,0 +1,1244 @@ +require "rexml/parent" +require "rexml/namespace" +require "rexml/attribute" +require "rexml/cdata" +require "rexml/xpath" +require "rexml/parseexception" + +module REXML + # An implementation note about namespaces: + # As we parse, when we find namespaces we put them in a hash and assign + # them a unique ID. We then convert the namespace prefix for the node + # to the unique ID. This makes namespace lookup much faster for the + # cost of extra memory use. We save the namespace prefix for the + # context node and convert it back when we write it. + @@namespaces = {} + + # Represents a tagged XML element. Elements are characterized by + # having children, attributes, and names, and can themselves be + # children. + class Element < Parent + include Namespace + + UNDEFINED = "UNDEFINED"; # The default name + + # Mechanisms for accessing attributes and child elements of this + # element. + attr_reader :attributes, :elements + # The context holds information about the processing environment, such as + # whitespace handling. + attr_accessor :context + + # Constructor + # arg:: + # if not supplied, will be set to the default value. + # If a String, the name of this object will be set to the argument. + # If an Element, the object will be shallowly cloned; name, + # attributes, and namespaces will be copied. Children will +not+ be + # copied. + # parent:: + # if supplied, must be a Parent, and will be used as + # the parent of this object. + # context:: + # If supplied, must be a hash containing context items. Context items + # include: + # * :respect_whitespace the value of this is :+all+ or an array of + # strings being the names of the elements to respect + # whitespace for. Defaults to :+all+. + # * :compress_whitespace the value can be :+all+ or an array of + # strings being the names of the elements to ignore whitespace on. + # Overrides :+respect_whitespace+. + # * :ignore_whitespace_nodes the value can be :+all+ or an array + # of strings being the names of the elements in which to ignore + # whitespace-only nodes. If this is set, Text nodes which contain only + # whitespace will not be added to the document tree. + # * :raw can be :+all+, or an array of strings being the names of + # the elements to process in raw mode. In raw mode, special + # characters in text is not converted to or from entities. + def initialize( arg = UNDEFINED, parent=nil, context=nil ) + super(parent) + + @elements = Elements.new(self) + @attributes = Attributes.new(self) + @context = context + + if arg.kind_of? String + self.name = arg + elsif arg.kind_of? Element + self.name = arg.expanded_name + arg.attributes.each_attribute{ |attribute| + @attributes << Attribute.new( attribute ) + } + @context = arg.context + end + end + + def inspect + rv = "<#@expanded_name" + + @attributes.each_attribute do |attr| + rv << " " + attr.write( rv, 0 ) + end + + if children.size > 0 + rv << "> ... " + else + rv << "/>" + end + end + + + # Creates a shallow copy of self. + # d = Document.new "" + # new_a = d.root.clone + # puts new_a # => "" + def clone + self.class.new self + end + + # Evaluates to the root node of the document that this element + # belongs to. If this element doesn't belong to a document, but does + # belong to another Element, the parent's root will be returned, until the + # earliest ancestor is found. + # + # Note that this is not the same as the document element. + # In the following example, is the document element, and the root + # node is the parent node of the document element. You may ask yourself + # why the root node is useful: consider the doctype and XML declaration, + # and any processing instructions before the document element... they + # are children of the root node, or siblings of the document element. + # The only time this isn't true is when an Element is created that is + # not part of any Document. In this case, the ancestor that has no + # parent acts as the root node. + # d = Document.new '' + # a = d[1] ; c = a[1][1] + # d.root_node == d # TRUE + # a.root_node # namely, d + # c.root_node # again, d + def root_node + parent.nil? ? self : parent.root_node + end + + def root + return elements[1] if self.kind_of? Document + return self if parent.kind_of? Document or parent.nil? + return parent.root + end + + # Evaluates to the document to which this element belongs, or nil if this + # element doesn't belong to a document. + def document + rt = root + rt.parent if rt + end + + # Evaluates to +true+ if whitespace is respected for this element. This + # is the case if: + # 1. Neither :+respect_whitespace+ nor :+compress_whitespace+ has any value + # 2. The context has :+respect_whitespace+ set to :+all+ or + # an array containing the name of this element, and + # :+compress_whitespace+ isn't set to :+all+ or an array containing the + # name of this element. + # The evaluation is tested against +expanded_name+, and so is namespace + # sensitive. + def whitespace + @whitespace = nil + if @context + if @context[:respect_whitespace] + @whitespace = (@context[:respect_whitespace] == :all or + @context[:respect_whitespace].include? expanded_name) + end + @whitespace = false if (@context[:compress_whitespace] and + (@context[:compress_whitespace] == :all or + @context[:compress_whitespace].include? expanded_name) + ) + end + @whitespace = true unless @whitespace == false + @whitespace + end + + def ignore_whitespace_nodes + @ignore_whitespace_nodes = false + if @context + if @context[:ignore_whitespace_nodes] + @ignore_whitespace_nodes = + (@context[:ignore_whitespace_nodes] == :all or + @context[:ignore_whitespace_nodes].include? expanded_name) + end + end + end + + # Evaluates to +true+ if raw mode is set for this element. This + # is the case if the context has :+raw+ set to :+all+ or + # an array containing the name of this element. + # + # The evaluation is tested against +expanded_name+, and so is namespace + # sensitive. + def raw + @raw = (@context and @context[:raw] and + (@context[:raw] == :all or + @context[:raw].include? expanded_name)) + @raw + end + + #once :whitespace, :raw, :ignore_whitespace_nodes + + ################################################# + # Namespaces # + ################################################# + + # Evaluates to an +Array+ containing the prefixes (names) of all defined + # namespaces at this context node. + # doc = Document.new("") + # doc.elements['//b'].prefixes # -> ['x', 'y'] + def prefixes + prefixes = [] + prefixes = parent.prefixes if parent + prefixes |= attributes.prefixes + return prefixes + end + + def namespaces + namespaces = {} + namespaces = parent.namespaces if parent + namespaces = namespaces.merge( attributes.namespaces ) + return namespaces + end + + # Evalutas to the URI for a prefix, or the empty string if no such + # namespace is declared for this element. Evaluates recursively for + # ancestors. Returns the default namespace, if there is one. + # prefix:: + # the prefix to search for. If not supplied, returns the default + # namespace if one exists + # Returns:: + # the namespace URI as a String, or nil if no such namespace + # exists. If the namespace is undefined, returns an empty string + # doc = Document.new("") + # b = doc.elements['//b'] + # b.namespace # -> '1' + # b.namespace("y") # -> '2' + def namespace(prefix=nil) + if prefix.nil? + prefix = prefix() + end + if prefix == '' + prefix = "xmlns" + else + prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns' + end + ns = attributes[ prefix ] + ns = parent.namespace(prefix) if ns.nil? and parent + ns = '' if ns.nil? and prefix == 'xmlns' + return ns + end + + # Adds a namespace to this element. + # prefix:: + # the prefix string, or the namespace URI if +uri+ is not + # supplied + # uri:: + # the namespace URI. May be nil, in which +prefix+ is used as + # the URI + # Evaluates to: this Element + # a = Element.new("a") + # a.add_namespace("xmlns:foo", "bar" ) + # a.add_namespace("foo", "bar") # shorthand for previous line + # a.add_namespace("twiddle") + # puts a #-> + def add_namespace( prefix, uri=nil ) + unless uri + @attributes["xmlns"] = prefix + else + prefix = "xmlns:#{prefix}" unless prefix =~ /^xmlns:/ + @attributes[ prefix ] = uri + end + self + end + + # Removes a namespace from this node. This only works if the namespace is + # actually declared in this node. If no argument is passed, deletes the + # default namespace. + # + # Evaluates to: this element + # doc = Document.new "" + # doc.root.delete_namespace + # puts doc # -> + # doc.root.delete_namespace 'foo' + # puts doc # -> + def delete_namespace namespace="xmlns" + namespace = "xmlns:#{namespace}" unless namespace == 'xmlns' + attribute = attributes.get_attribute(namespace) + attribute.remove unless attribute.nil? + self + end + + ################################################# + # Elements # + ################################################# + + # Adds a child to this element, optionally setting attributes in + # the element. + # element:: + # optional. If Element, the element is added. + # Otherwise, a new Element is constructed with the argument (see + # Element.initialize). + # attrs:: + # If supplied, must be a Hash containing String name,value + # pairs, which will be used to set the attributes of the new Element. + # Returns:: the Element that was added + # el = doc.add_element 'my-tag' + # el = doc.add_element 'my-tag', {'attr1'=>'val1', 'attr2'=>'val2'} + # el = Element.new 'my-tag' + # doc.add_element el + def add_element element, attrs=nil + raise "First argument must be either an element name, or an Element object" if element.nil? + el = @elements.add(element) + attrs.each do |key, value| + el.attributes[key]=value + end if attrs.kind_of? Hash + el + end + + # Deletes a child element. + # element:: + # Must be an +Element+, +String+, or +Integer+. If Element, + # the element is removed. If String, the element is found (via XPath) + # and removed. This means that any parent can remove any + # descendant. If Integer, the Element indexed by that number will be + # removed. + # Returns:: the element that was removed. + # doc.delete_element "/a/b/c[@id='4']" + # doc.delete_element doc.elements["//k"] + # doc.delete_element 1 + def delete_element element + @elements.delete element + end + + # Evaluates to +true+ if this element has at least one child Element + # doc = Document.new "Text" + # doc.root.has_elements # -> true + # doc.elements["/a/b"].has_elements # -> false + # doc.elements["/a/c"].has_elements # -> false + def has_elements? + !@elements.empty? + end + + # Iterates through the child elements, yielding for each Element that + # has a particular attribute set. + # key:: + # the name of the attribute to search for + # value:: + # the value of the attribute + # max:: + # (optional) causes this method to return after yielding + # for this number of matching children + # name:: + # (optional) if supplied, this is an XPath that filters + # the children to check. + # + # doc = Document.new "" + # # Yields b, c, d + # doc.root.each_element_with_attribute( 'id' ) {|e| p e} + # # Yields b, d + # doc.root.each_element_with_attribute( 'id', '1' ) {|e| p e} + # # Yields b + # doc.root.each_element_with_attribute( 'id', '1', 1 ) {|e| p e} + # # Yields d + # doc.root.each_element_with_attribute( 'id', '1', 0, 'd' ) {|e| p e} + def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element + each_with_something( proc {|child| + if value.nil? + child.attributes[key] != nil + else + child.attributes[key]==value + end + }, max, name, &block ) + end + + # Iterates through the children, yielding for each Element that + # has a particular text set. + # text:: + # the text to search for. If nil, or not supplied, will itterate + # over all +Element+ children that contain at least one +Text+ node. + # max:: + # (optional) causes this method to return after yielding + # for this number of matching children + # name:: + # (optional) if supplied, this is an XPath that filters + # the children to check. + # + # doc = Document.new 'bbd' + # # Yields b, c, d + # doc.each_element_with_text {|e|p e} + # # Yields b, c + # doc.each_element_with_text('b'){|e|p e} + # # Yields b + # doc.each_element_with_text('b', 1){|e|p e} + # # Yields d + # doc.each_element_with_text(nil, 0, 'd'){|e|p e} + def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element + each_with_something( proc {|child| + if text.nil? + child.has_text? + else + child.text == text + end + }, max, name, &block ) + end + + # Synonym for Element.elements.each + def each_element( xpath=nil, &block ) # :yields: Element + @elements.each( xpath, &block ) + end + + # Synonym for Element.to_a + # This is a little slower than calling elements.each directly. + # xpath:: any XPath by which to search for elements in the tree + # Returns:: an array of Elements that match the supplied path + def get_elements( xpath ) + @elements.to_a( xpath ) + end + + # Returns the next sibling that is an element, or nil if there is + # no Element sibling after this one + # doc = Document.new 'text' + # doc.root.elements['b'].next_element #-> + # doc.root.elements['c'].next_element #-> nil + def next_element + element = next_sibling + element = element.next_sibling until element.nil? or element.kind_of? Element + return element + end + + # Returns the previous sibling that is an element, or nil if there is + # no Element sibling prior to this one + # doc = Document.new 'text' + # doc.root.elements['c'].previous_element #-> + # doc.root.elements['b'].previous_element #-> nil + def previous_element + element = previous_sibling + element = element.previous_sibling until element.nil? or element.kind_of? Element + return element + end + + + ################################################# + # Text # + ################################################# + + # Evaluates to +true+ if this element has at least one Text child + def has_text? + not text().nil? + end + + # A convenience method which returns the String value of the _first_ + # child text element, if one exists, and +nil+ otherwise. + # + # Note that an element may have multiple Text elements, perhaps + # separated by other children. Be aware that this method only returns + # the first Text node. + # + # This method returns the +value+ of the first text child node, which + # ignores the +raw+ setting, so always returns normalized text. See + # the Text::value documentation. + # + # doc = Document.new "

some text this is bold! more text

" + # # The element 'p' has two text elements, "some text " and " more text". + # doc.root.text #-> "some text " + def text( path = nil ) + rv = get_text(path) + return rv.value unless rv.nil? + nil + end + + # Returns the first child Text node, if any, or +nil+ otherwise. + # This method returns the actual +Text+ node, rather than the String content. + # doc = Document.new "

some text this is bold! more text

" + # # The element 'p' has two text elements, "some text " and " more text". + # doc.root.get_text.value #-> "some text " + def get_text path = nil + rv = nil + if path + element = @elements[ path ] + rv = element.get_text unless element.nil? + else + rv = @children.find { |node| node.kind_of? Text } + end + return rv + end + + # Sets the first Text child of this object. See text() for a + # discussion about Text children. + # + # If a Text child already exists, the child is replaced by this + # content. This means that Text content can be deleted by calling + # this method with a nil argument. In this case, the next Text + # child becomes the first Text child. In no case is the order of + # any siblings disturbed. + # text:: + # If a String, a new Text child is created and added to + # this Element as the first Text child. If Text, the text is set + # as the first Child element. If nil, then any existing first Text + # child is removed. + # Returns:: this Element. + # doc = Document.new '' + # doc.root.text = 'Sean' #-> 'Sean' + # doc.root.text = 'Elliott' #-> 'Elliott' + # doc.root.add_element 'c' #-> 'Elliott' + # doc.root.text = 'Russell' #-> 'Russell' + # doc.root.text = nil #-> '' + def text=( text ) + if text.kind_of? String + text = Text.new( text, whitespace(), nil, raw() ) + elsif text and !text.kind_of? Text + text = Text.new( text.to_s, whitespace(), nil, raw() ) + end + old_text = get_text + if text.nil? + old_text.remove unless old_text.nil? + else + if old_text.nil? + self << text + else + old_text.replace_with( text ) + end + end + return self + end + + # A helper method to add a Text child. Actual Text instances can + # be added with regular Parent methods, such as add() and <<() + # text:: + # if a String, a new Text instance is created and added + # to the parent. If Text, the object is added directly. + # Returns:: this Element + # e = Element.new('a') #-> + # e.add_text 'foo' #-> foo + # e.add_text Text.new(' bar') #-> foo bar + # Note that at the end of this example, the branch has 3 nodes; the 'e' + # element and 2 Text node children. + def add_text( text ) + if text.kind_of? String + if @children[-1].kind_of? Text + @children[-1] << text + return + end + text = Text.new( text, whitespace(), nil, raw() ) + end + self << text unless text.nil? + return self + end + + def node_type + :element + end + + def xpath + path_elements = [] + cur = self + path_elements << __to_xpath_helper( self ) + while cur.parent + cur = cur.parent + path_elements << __to_xpath_helper( cur ) + end + return path_elements.reverse.join( "/" ) + end + + ################################################# + # Attributes # + ################################################# + + def attribute( name, namespace=nil ) + prefix = nil + if namespaces.respond_to? :key + prefix = namespaces.key(namespace) if namespace + else + prefix = namespaces.index(namespace) if namespace + end + prefix = nil if prefix == 'xmlns' + + ret_val = + attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" ) + + return ret_val unless ret_val.nil? + return nil if prefix.nil? + + # now check that prefix'es namespace is not the same as the + # default namespace + return nil unless ( namespaces[ prefix ] == namespaces[ 'xmlns' ] ) + + attributes.get_attribute( name ) + + end + + # Evaluates to +true+ if this element has any attributes set, false + # otherwise. + def has_attributes? + return !@attributes.empty? + end + + # Adds an attribute to this element, overwriting any existing attribute + # by the same name. + # key:: + # can be either an Attribute or a String. If an Attribute, + # the attribute is added to the list of Element attributes. If String, + # the argument is used as the name of the new attribute, and the value + # parameter must be supplied. + # value:: + # Required if +key+ is a String, and ignored if the first argument is + # an Attribute. This is a String, and is used as the value + # of the new Attribute. This should be the unnormalized value of the + # attribute (without entities). + # Returns:: the Attribute added + # e = Element.new 'e' + # e.add_attribute( 'a', 'b' ) #-> + # e.add_attribute( 'x:a', 'c' ) #-> + # e.add_attribute Attribute.new('b', 'd') #-> + def add_attribute( key, value=nil ) + if key.kind_of? Attribute + @attributes << key + else + @attributes[key] = value + end + end + + # Add multiple attributes to this element. + # hash:: is either a hash, or array of arrays + # el.add_attributes( {"name1"=>"value1", "name2"=>"value2"} ) + # el.add_attributes( [ ["name1","value1"], ["name2"=>"value2"] ] ) + def add_attributes hash + if hash.kind_of? Hash + hash.each_pair {|key, value| @attributes[key] = value } + elsif hash.kind_of? Array + hash.each { |value| @attributes[ value[0] ] = value[1] } + end + end + + # Removes an attribute + # key:: + # either an Attribute or a String. In either case, the + # attribute is found by matching the attribute name to the argument, + # and then removed. If no attribute is found, no action is taken. + # Returns:: + # the attribute removed, or nil if this Element did not contain + # a matching attribute + # e = Element.new('E') + # e.add_attribute( 'name', 'Sean' ) #-> + # r = e.add_attribute( 'sur:name', 'Russell' ) #-> + # e.delete_attribute( 'name' ) #-> + # e.delete_attribute( r ) #-> + def delete_attribute(key) + attr = @attributes.get_attribute(key) + attr.remove unless attr.nil? + end + + ################################################# + # Other Utilities # + ################################################# + + # Get an array of all CData children. + # IMMUTABLE + def cdatas + find_all { |child| child.kind_of? CData }.freeze + end + + # Get an array of all Comment children. + # IMMUTABLE + def comments + find_all { |child| child.kind_of? Comment }.freeze + end + + # Get an array of all Instruction children. + # IMMUTABLE + def instructions + find_all { |child| child.kind_of? Instruction }.freeze + end + + # Get an array of all Text children. + # IMMUTABLE + def texts + find_all { |child| child.kind_of? Text }.freeze + end + + # == DEPRECATED + # See REXML::Formatters + # + # Writes out this element, and recursively, all children. + # 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 this number of spaces, and children will be + # indented an additional amount. 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 parse tree of the document + # ie_hack:: + # Internet Explorer is the worst piece of crap to have ever been + # written, with the possible exception of Windows itself. Since IE is + # unable to parse proper XML, we have to provide a hack to generate XML + # that IE's limited abilities can handle. This hack inserts a space + # before the /> on empty tags. Defaults to false + # + # out = '' + # doc.write( out ) #-> doc is written to the string 'out' + # doc.write( $stdout ) #-> doc written to the console + def write(output=$stdout, indent=-1, transitive=false, ie_hack=false) + Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters") + formatter = if indent > -1 + if 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 + + + private + def __to_xpath_helper node + rv = node.expanded_name.clone + if node.parent + results = node.parent.find_all {|n| + n.kind_of?(REXML::Element) and n.expanded_name == node.expanded_name + } + if results.length > 1 + idx = results.index( node ) + rv << "[#{idx+1}]" + end + end + rv + end + + # A private helper method + def each_with_something( test, max=0, name=nil ) + num = 0 + @elements.each( name ){ |child| + yield child if test.call(child) and num += 1 + return if max>0 and num == max + } + end + end + + ######################################################################## + # ELEMENTS # + ######################################################################## + + # A class which provides filtering of children for Elements, and + # XPath search support. You are expected to only encounter this class as + # the element.elements object. Therefore, you are + # _not_ expected to instantiate this yourself. + class Elements + include Enumerable + # Constructor + # parent:: the parent Element + def initialize parent + @element = parent + end + + # Fetches a child element. Filters only Element children, regardless of + # the XPath match. + # index:: + # the search parameter. This is either an Integer, which + # will be used to find the index'th child Element, or an XPath, + # which will be used to search for the Element. Because + # of the nature of XPath searches, any element in the connected XML + # document can be fetched through any other element. The + # Integer index is 1-based, not 0-based. This means that the first + # child element is at index 1, not 0, and the +n+th element is at index + # +n+, not n-1. This is because XPath indexes element children + # starting from 1, not 0, and the indexes should be the same. + # name:: + # optional, and only used in the first argument is an + # Integer. In that case, the index'th child Element that has the + # supplied name will be returned. Note again that the indexes start at 1. + # Returns:: the first matching Element, or nil if no child matched + # doc = Document.new '' + # doc.root.elements[1] #-> + # doc.root.elements['c'] #-> + # doc.root.elements[2,'c'] #-> + def []( index, name=nil) + if index.kind_of? Integer + raise "index (#{index}) must be >= 1" if index < 1 + name = literalize(name) if name + num = 0 + @element.find { |child| + child.kind_of? Element and + (name.nil? ? true : child.has_name?( name )) and + (num += 1) == index + } + else + return XPath::first( @element, index ) + #{ |element| + # return element if element.kind_of? Element + #} + #return nil + end + end + + # Sets an element, replacing any previous matching element. If no + # existing element is found ,the element is added. + # index:: Used to find a matching element to replace. See [](). + # element:: + # The element to replace the existing element with + # the previous element + # Returns:: nil if no previous element was found. + # + # doc = Document.new '' + # doc.root.elements[10] = Element.new('b') #-> + # doc.root.elements[1] #-> + # doc.root.elements[1] = Element.new('c') #-> + # doc.root.elements['c'] = Element.new('d') #-> + def []=( index, element ) + previous = self[index] + if previous.nil? + @element.add element + else + previous.replace_with element + end + return previous + end + + # Returns +true+ if there are no +Element+ children, +false+ otherwise + def empty? + @element.find{ |child| child.kind_of? Element}.nil? + end + + # Returns the index of the supplied child (starting at 1), or -1 if + # the element is not a child + # element:: an +Element+ child + def index element + rv = 0 + found = @element.find do |child| + child.kind_of? Element and + (rv += 1) and + child == element + end + return rv if found == element + return -1 + end + + # Deletes a child Element + # element:: + # Either an Element, which is removed directly; an + # xpath, where the first matching child is removed; or an Integer, + # where the n'th Element is removed. + # Returns:: the removed child + # doc = Document.new '' + # b = doc.root.elements[1] + # doc.root.elements.delete b #-> + # doc.elements.delete("a/c[@id='1']") #-> + # doc.root.elements.delete 1 #-> + def delete element + if element.kind_of? Element + @element.delete element + else + el = self[element] + el.remove if el + end + end + + # Removes multiple elements. Filters for Element children, regardless of + # XPath matching. + # xpath:: all elements matching this String path are removed. + # Returns:: an Array of Elements that have been removed + # doc = Document.new '' + # deleted = doc.elements.delete_all 'a/c' #-> [, , , ] + def delete_all( xpath ) + rv = [] + XPath::each( @element, xpath) {|element| + rv << element if element.kind_of? Element + } + rv.each do |element| + @element.delete element + element.remove + end + return rv + end + + # Adds an element + # element:: + # if supplied, is either an Element, String, or + # Source (see Element.initialize). If not supplied or nil, a + # new, default Element will be constructed + # Returns:: the added Element + # a = Element.new('a') + # a.elements.add(Element.new('b')) #-> + # a.elements.add('c') #-> + def add element=nil + rv = nil + if element.nil? + Element.new("", self, @element.context) + elsif not element.kind_of?(Element) + Element.new(element, self, @element.context) + else + @element << element + element.context = @element.context + element + end + end + + alias :<< :add + + # Iterates through all of the child Elements, optionally filtering + # them by a given XPath + # xpath:: + # optional. If supplied, this is a String XPath, and is used to + # filter the children, so that only matching children are yielded. Note + # that XPaths are automatically filtered for Elements, so that + # non-Element children will not be yielded + # doc = Document.new 'sean' + # doc.root.each {|e|p e} #-> Yields b, c, d, b, c, d elements + # doc.root.each('b') {|e|p e} #-> Yields b, b elements + # doc.root.each('child::node()') {|e|p e} + # #-> Yields , , , , , + # XPath.each(doc.root, 'child::node()', &block) + # #-> Yields , , , sean, , , + def each( xpath=nil, &block) + XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element } + end + + def collect( xpath=nil, &block ) + collection = [] + XPath::each( @element, xpath ) {|e| + collection << yield(e) if e.kind_of?(Element) + } + collection + end + + def inject( xpath=nil, initial=nil, &block ) + first = true + XPath::each( @element, xpath ) {|e| + if (e.kind_of? Element) + if (first and initial == nil) + initial = e + first = false + else + initial = yield( initial, e ) if e.kind_of? Element + end + end + } + initial + end + + # Returns the number of +Element+ children of the parent object. + # doc = Document.new 'seanelliottrussell' + # doc.root.size #-> 6, 3 element and 3 text nodes + # doc.root.elements.size #-> 3 + def size + count = 0 + @element.each {|child| count+=1 if child.kind_of? Element } + count + end + + # Returns an Array of Element children. An XPath may be supplied to + # filter the children. Only Element children are returned, even if the + # supplied XPath matches non-Element children. + # doc = Document.new 'seanelliott' + # doc.root.elements.to_a #-> [ , ] + # doc.root.elements.to_a("child::node()") #-> [ , ] + # XPath.match(doc.root, "child::node()") #-> [ sean, , elliott, ] + def to_a( xpath=nil ) + rv = XPath.match( @element, xpath ) + return rv.find_all{|e| e.kind_of? Element} if xpath + rv + end + + private + # Private helper class. Removes quotes from quoted strings + def literalize name + name = name[1..-2] if name[0] == ?' or name[0] == ?" #' + name + end + end + + ######################################################################## + # ATTRIBUTES # + ######################################################################## + + # A class that defines the set of Attributes of an Element and provides + # operations for accessing elements in that set. + class Attributes < Hash + # Constructor + # element:: the Element of which this is an Attribute + def initialize element + @element = element + end + + # Fetches an attribute value. If you want to get the Attribute itself, + # use get_attribute() + # name:: an XPath attribute name. Namespaces are relevant here. + # Returns:: + # the String value of the matching attribute, or +nil+ if no + # matching attribute was found. This is the unnormalized value + # (with entities expanded). + # + # doc = Document.new "" + # doc.root.attributes['att'] #-> '<' + # doc.root.attributes['bar:att'] #-> '2' + def [](name) + attr = get_attribute(name) + return attr.value unless attr.nil? + return nil + end + + def to_a + values.flatten + end + + # Returns the number of attributes the owning Element contains. + # doc = Document "" + # doc.root.attributes.length #-> 3 + def length + c = 0 + each_attribute { c+=1 } + c + end + alias :size :length + + # Itterates over the attributes of an Element. Yields actual Attribute + # nodes, not String values. + # + # doc = Document.new '' + # doc.root.attributes.each_attribute {|attr| + # p attr.expanded_name+" => "+attr.value + # } + def each_attribute # :yields: attribute + each_value do |val| + if val.kind_of? Attribute + yield val + else + val.each_value { |atr| yield atr } + end + end + end + + # Itterates over each attribute of an Element, yielding the expanded name + # and value as a pair of Strings. + # + # doc = Document.new '' + # doc.root.attributes.each {|name, value| p name+" => "+value } + def each + each_attribute do |attr| + yield [attr.expanded_name, attr.value] + end + end + + # Fetches an attribute + # name:: + # the name by which to search for the attribute. Can be a + # prefix:name namespace name. + # Returns:: The first matching attribute, or nil if there was none. This + # value is an Attribute node, not the String value of the attribute. + # doc = Document.new '' + # doc.root.attributes.get_attribute("foo").value #-> "2" + # doc.root.attributes.get_attribute("x:foo").value #-> "1" + def get_attribute( name ) + attr = fetch( name, nil ) + if attr.nil? + return nil if name.nil? + # Look for prefix + name =~ Namespace::NAMESPLIT + prefix, n = $1, $2 + if prefix + attr = fetch( n, nil ) + # check prefix + if attr == nil + elsif attr.kind_of? Attribute + return attr if prefix == attr.prefix + else + attr = attr[ prefix ] + return attr + end + end + element_document = @element.document + if element_document and element_document.doctype + expn = @element.expanded_name + expn = element_document.doctype.name if expn.size == 0 + attr_val = element_document.doctype.attribute_of(expn, name) + return Attribute.new( name, attr_val ) if attr_val + end + return nil + end + if attr.kind_of? Hash + attr = attr[ @element.prefix ] + end + return attr + end + + # Sets an attribute, overwriting any existing attribute value by the + # same name. Namespace is significant. + # name:: the name of the attribute + # value:: + # (optional) If supplied, the value of the attribute. If + # nil, any existing matching attribute is deleted. + # Returns:: + # Owning element + # doc = Document.new "" + # doc.root.attributes['y:foo'] = '2' + # doc.root.attributes['foo'] = '4' + # doc.root.attributes['x:foo'] = nil + def []=( name, value ) + if value.nil? # Delete the named attribute + attr = get_attribute(name) + delete attr + return + end + element_document = @element.document + unless value.kind_of? Attribute + if @element.document and @element.document.doctype + value = Text::normalize( value, @element.document.doctype ) + else + value = Text::normalize( value, nil ) + end + value = Attribute.new(name, value) + end + value.element = @element + old_attr = fetch(value.name, nil) + if old_attr.nil? + store(value.name, value) + elsif old_attr.kind_of? Hash + old_attr[value.prefix] = value + elsif old_attr.prefix != value.prefix + # Check for conflicting namespaces + raise ParseException.new( + "Namespace conflict in adding attribute \"#{value.name}\": "+ + "Prefix \"#{old_attr.prefix}\" = "+ + "\"#{@element.namespace(old_attr.prefix)}\" and prefix "+ + "\"#{value.prefix}\" = \"#{@element.namespace(value.prefix)}\"") if + value.prefix != "xmlns" and old_attr.prefix != "xmlns" and + @element.namespace( old_attr.prefix ) == + @element.namespace( value.prefix ) + store value.name, { old_attr.prefix => old_attr, + value.prefix => value } + else + store value.name, value + end + return @element + end + + # Returns an array of Strings containing all of the prefixes declared + # by this set of # attributes. The array does not include the default + # namespace declaration, if one exists. + # doc = Document.new("") + # prefixes = doc.root.attributes.prefixes #-> ['x', 'y'] + def prefixes + ns = [] + each_attribute do |attribute| + ns << attribute.name if attribute.prefix == 'xmlns' + end + if @element.document and @element.document.doctype + expn = @element.expanded_name + expn = @element.document.doctype.name if expn.size == 0 + @element.document.doctype.attributes_of(expn).each { + |attribute| + ns << attribute.name if attribute.prefix == 'xmlns' + } + end + ns + end + + def namespaces + namespaces = {} + each_attribute do |attribute| + namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns' + end + if @element.document and @element.document.doctype + expn = @element.expanded_name + expn = @element.document.doctype.name if expn.size == 0 + @element.document.doctype.attributes_of(expn).each { + |attribute| + namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns' + } + end + namespaces + end + + # Removes an attribute + # attribute:: + # either a String, which is the name of the attribute to remove -- + # namespaces are significant here -- or the attribute to remove. + # Returns:: the owning element + # doc = Document.new "" + # doc.root.attributes.delete 'foo' #-> " + # doc.root.attributes.delete 'x:foo' #-> " + # attr = doc.root.attributes.get_attribute('y:foo') + # doc.root.attributes.delete attr #-> " + def delete( attribute ) + name = nil + prefix = nil + if attribute.kind_of? Attribute + name = attribute.name + prefix = attribute.prefix + else + attribute =~ Namespace::NAMESPLIT + prefix, name = $1, $2 + prefix = '' unless prefix + end + old = fetch(name, nil) + attr = nil + if old.kind_of? Hash # the supplied attribute is one of many + attr = old.delete(prefix) + if old.size == 1 + repl = nil + old.each_value{|v| repl = v} + store name, repl + end + elsif old.nil? + return @element + else # the supplied attribute is a top-level one + attr = old + res = super(name) + end + @element + end + + # Adds an attribute, overriding any existing attribute by the + # same name. Namespaces are significant. + # attribute:: An Attribute + def add( attribute ) + self[attribute.name] = attribute + end + + alias :<< :add + + # Deletes all attributes matching a name. Namespaces are significant. + # name:: + # A String; all attributes that match this path will be removed + # Returns:: an Array of the Attributes that were removed + def delete_all( name ) + rv = [] + each_attribute { |attribute| + rv << attribute if attribute.expanded_name == name + } + rv.each{ |attr| attr.remove } + return rv + end + + # The +get_attribute_ns+ method retrieves a method by its namespace + # and name. Thus it is possible to reliably identify an attribute + # even if an XML processor has changed the prefix. + # + # Method contributed by Henrik Martensson + def get_attribute_ns(namespace, name) + result = nil + each_attribute() { |attribute| + if name == attribute.name && + namespace == attribute.namespace() + # foo will match xmlns:foo, but only if foo isn't also an attribute + result = attribute if !result or !namespace.empty? or + !attribute.fully_expanded_name.index(':') + end + } + result + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encoding.rb b/vendor/plugins/rexml/lib/rexml/encoding.rb new file mode 100644 index 00000000..608c69cd --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encoding.rb @@ -0,0 +1,71 @@ +# -*- mode: ruby; ruby-indent-level: 2; indent-tabs-mode: t; tab-width: 2 -*- vim: sw=2 ts=2 +module REXML + module Encoding + @encoding_methods = {} + def self.register(enc, &block) + @encoding_methods[enc] = block + end + def self.apply(obj, enc) + @encoding_methods[enc][obj] + end + def self.encoding_method(enc) + @encoding_methods[enc] + end + + # Native, default format is UTF-8, so it is declared here rather than in + # an encodings/ definition. + UTF_8 = 'UTF-8' + UTF_16 = 'UTF-16' + UNILE = 'UNILE' + + # ID ---> Encoding name + attr_reader :encoding + def encoding=( enc ) + old_verbosity = $VERBOSE + begin + $VERBOSE = false + enc = enc.nil? ? nil : enc.upcase + return false if defined? @encoding and enc == @encoding + if enc and enc != UTF_8 + @encoding = enc + raise ArgumentError, "Bad encoding name #@encoding" unless @encoding =~ /^[\w-]+$/ + @encoding.untaint + begin + require 'rexml/encodings/ICONV.rb' + Encoding.apply(self, "ICONV") + rescue LoadError, Exception + begin + enc_file = File.join( "rexml", "encodings", "#@encoding.rb" ) + require enc_file + Encoding.apply(self, @encoding) + rescue LoadError => err + puts err.message + raise ArgumentError, "No decoder found for encoding #@encoding. Please install iconv." + end + end + else + @encoding = UTF_8 + require 'rexml/encodings/UTF-8.rb' + Encoding.apply(self, @encoding) + end + ensure + $VERBOSE = old_verbosity + end + true + end + + def check_encoding str + # We have to recognize UTF-16, LSB UTF-16, and UTF-8 + if str[0,2] == "\xfe\xff" + str[0,2] = "" + return UTF_16 + elsif str[0,2] == "\xff\xfe" + str[0,2] = "" + return UNILE + end + str =~ /^\s*<\?xml\s+version\s*=\s*(['"]).*?\1\s+encoding\s*=\s*(["'])(.*?)\2/m + return $3.upcase if $3 + return UTF_8 + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/CP-1252.rb b/vendor/plugins/rexml/lib/rexml/encodings/CP-1252.rb new file mode 100644 index 00000000..8675f9ff --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/CP-1252.rb @@ -0,0 +1,103 @@ +# +# This class was contributed by Mikko Tiihonen mikko DOT tiihonen AT hut DOT fi +# +module REXML + module Encoding + register( "CP-1252" ) do |o| + class << o + alias encode encode_cp1252 + alias decode decode_cp1252 + end + end + + # Convert from UTF-8 + def encode_cp1252(content) + array_utf8 = content.unpack('U*') + array_enc = [] + array_utf8.each do |num| + case num + # shortcut first bunch basic characters + when 0..0xFF; array_enc << num + # characters added compared to iso-8859-1 + when 0x20AC; array_enc << 0x80 # 0xe2 0x82 0xac + when 0x201A; array_enc << 0x82 # 0xe2 0x82 0x9a + when 0x0192; array_enc << 0x83 # 0xc6 0x92 + when 0x201E; array_enc << 0x84 # 0xe2 0x82 0x9e + when 0x2026; array_enc << 0x85 # 0xe2 0x80 0xa6 + when 0x2020; array_enc << 0x86 # 0xe2 0x80 0xa0 + when 0x2021; array_enc << 0x87 # 0xe2 0x80 0xa1 + when 0x02C6; array_enc << 0x88 # 0xcb 0x86 + when 0x2030; array_enc << 0x89 # 0xe2 0x80 0xb0 + when 0x0160; array_enc << 0x8A # 0xc5 0xa0 + when 0x2039; array_enc << 0x8B # 0xe2 0x80 0xb9 + when 0x0152; array_enc << 0x8C # 0xc5 0x92 + when 0x017D; array_enc << 0x8E # 0xc5 0xbd + when 0x2018; array_enc << 0x91 # 0xe2 0x80 0x98 + when 0x2019; array_enc << 0x92 # 0xe2 0x80 0x99 + when 0x201C; array_enc << 0x93 # 0xe2 0x80 0x9c + when 0x201D; array_enc << 0x94 # 0xe2 0x80 0x9d + when 0x2022; array_enc << 0x95 # 0xe2 0x80 0xa2 + when 0x2013; array_enc << 0x96 # 0xe2 0x80 0x93 + when 0x2014; array_enc << 0x97 # 0xe2 0x80 0x94 + when 0x02DC; array_enc << 0x98 # 0xcb 0x9c + when 0x2122; array_enc << 0x99 # 0xe2 0x84 0xa2 + when 0x0161; array_enc << 0x9A # 0xc5 0xa1 + when 0x203A; array_enc << 0x9B # 0xe2 0x80 0xba + when 0x0152; array_enc << 0x9C # 0xc5 0x93 + when 0x017E; array_enc << 0x9E # 0xc5 0xbe + when 0x0178; array_enc << 0x9F # 0xc5 0xb8 + else + # all remaining basic characters can be used directly + if num <= 0xFF + array_enc << num + else + # Numeric entity (&#nnnn;); shard by Stefan Scholl + array_enc.concat "&\##{num};".unpack('C*') + end + end + end + array_enc.pack('C*') + end + + # Convert to UTF-8 + def decode_cp1252(str) + array_latin9 = str.unpack('C*') + array_enc = [] + array_latin9.each do |num| + case num + # characters that added compared to iso-8859-1 + when 0x80; array_enc << 0x20AC # 0xe2 0x82 0xac + when 0x82; array_enc << 0x201A # 0xe2 0x82 0x9a + when 0x83; array_enc << 0x0192 # 0xc6 0x92 + when 0x84; array_enc << 0x201E # 0xe2 0x82 0x9e + when 0x85; array_enc << 0x2026 # 0xe2 0x80 0xa6 + when 0x86; array_enc << 0x2020 # 0xe2 0x80 0xa0 + when 0x87; array_enc << 0x2021 # 0xe2 0x80 0xa1 + when 0x88; array_enc << 0x02C6 # 0xcb 0x86 + when 0x89; array_enc << 0x2030 # 0xe2 0x80 0xb0 + when 0x8A; array_enc << 0x0160 # 0xc5 0xa0 + when 0x8B; array_enc << 0x2039 # 0xe2 0x80 0xb9 + when 0x8C; array_enc << 0x0152 # 0xc5 0x92 + when 0x8E; array_enc << 0x017D # 0xc5 0xbd + when 0x91; array_enc << 0x2018 # 0xe2 0x80 0x98 + when 0x92; array_enc << 0x2019 # 0xe2 0x80 0x99 + when 0x93; array_enc << 0x201C # 0xe2 0x80 0x9c + when 0x94; array_enc << 0x201D # 0xe2 0x80 0x9d + when 0x95; array_enc << 0x2022 # 0xe2 0x80 0xa2 + when 0x96; array_enc << 0x2013 # 0xe2 0x80 0x93 + when 0x97; array_enc << 0x2014 # 0xe2 0x80 0x94 + when 0x98; array_enc << 0x02DC # 0xcb 0x9c + when 0x99; array_enc << 0x2122 # 0xe2 0x84 0xa2 + when 0x9A; array_enc << 0x0161 # 0xc5 0xa1 + when 0x9B; array_enc << 0x203A # 0xe2 0x80 0xba + when 0x9C; array_enc << 0x0152 # 0xc5 0x93 + when 0x9E; array_enc << 0x017E # 0xc5 0xbe + when 0x9F; array_enc << 0x0178 # 0xc5 0xb8 + else + array_enc << num + end + end + array_enc.pack('U*') + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/EUC-JP.rb b/vendor/plugins/rexml/lib/rexml/encodings/EUC-JP.rb new file mode 100644 index 00000000..db37b6bf --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/EUC-JP.rb @@ -0,0 +1,35 @@ +module REXML + module Encoding + begin + require 'uconv' + + def decode_eucjp(str) + Uconv::euctou8(str) + end + + def encode_eucjp content + Uconv::u8toeuc(content) + end + rescue LoadError + require 'nkf' + + EUCTOU8 = '-Ewm0' + U8TOEUC = '-Wem0' + + def decode_eucjp(str) + NKF.nkf(EUCTOU8, str) + end + + def encode_eucjp content + NKF.nkf(U8TOEUC, content) + end + end + + register("EUC-JP") do |obj| + class << obj + alias decode decode_eucjp + alias encode encode_eucjp + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/ICONV.rb b/vendor/plugins/rexml/lib/rexml/encodings/ICONV.rb new file mode 100644 index 00000000..172fba7c --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/ICONV.rb @@ -0,0 +1,22 @@ +require "iconv" +raise LoadError unless defined? Iconv + +module REXML + module Encoding + def decode_iconv(str) + Iconv.conv(UTF_8, @encoding, str) + end + + def encode_iconv(content) + Iconv.conv(@encoding, UTF_8, content) + end + + register("ICONV") do |obj| + Iconv.conv(UTF_8, obj.encoding, nil) + class << obj + alias decode decode_iconv + alias encode encode_iconv + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/ISO-8859-1.rb b/vendor/plugins/rexml/lib/rexml/encodings/ISO-8859-1.rb new file mode 100644 index 00000000..2873d13b --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/ISO-8859-1.rb @@ -0,0 +1,7 @@ +require 'rexml/encodings/US-ASCII' + +module REXML + module Encoding + register("ISO-8859-1", &encoding_method("US-ASCII")) + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/ISO-8859-15.rb b/vendor/plugins/rexml/lib/rexml/encodings/ISO-8859-15.rb new file mode 100644 index 00000000..8dea0d38 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/ISO-8859-15.rb @@ -0,0 +1,72 @@ +# +# This class was contributed by Mikko Tiihonen mikko DOT tiihonen AT hut DOT fi +# +module REXML + module Encoding + register("ISO-8859-15") do |o| + alias encode to_iso_8859_15 + alias decode from_iso_8859_15 + end + + # Convert from UTF-8 + def to_iso_8859_15(content) + array_utf8 = content.unpack('U*') + array_enc = [] + array_utf8.each do |num| + case num + # shortcut first bunch basic characters + when 0..0xA3; array_enc << num + # characters removed compared to iso-8859-1 + when 0xA4; array_enc << '¤' + when 0xA6; array_enc << '¦' + when 0xA8; array_enc << '¨' + when 0xB4; array_enc << '´' + when 0xB8; array_enc << '¸' + when 0xBC; array_enc << '¼' + when 0xBD; array_enc << '½' + when 0xBE; array_enc << '¾' + # characters added compared to iso-8859-1 + when 0x20AC; array_enc << 0xA4 # 0xe2 0x82 0xac + when 0x0160; array_enc << 0xA6 # 0xc5 0xa0 + when 0x0161; array_enc << 0xA8 # 0xc5 0xa1 + when 0x017D; array_enc << 0xB4 # 0xc5 0xbd + when 0x017E; array_enc << 0xB8 # 0xc5 0xbe + when 0x0152; array_enc << 0xBC # 0xc5 0x92 + when 0x0153; array_enc << 0xBD # 0xc5 0x93 + when 0x0178; array_enc << 0xBE # 0xc5 0xb8 + else + # all remaining basic characters can be used directly + if num <= 0xFF + array_enc << num + else + # Numeric entity (&#nnnn;); shard by Stefan Scholl + array_enc.concat "&\##{num};".unpack('C*') + end + end + end + array_enc.pack('C*') + end + + # Convert to UTF-8 + def from_iso_8859_15(str) + array_latin9 = str.unpack('C*') + array_enc = [] + array_latin9.each do |num| + case num + # characters that differ compared to iso-8859-1 + when 0xA4; array_enc << 0x20AC + when 0xA6; array_enc << 0x0160 + when 0xA8; array_enc << 0x0161 + when 0xB4; array_enc << 0x017D + when 0xB8; array_enc << 0x017E + when 0xBC; array_enc << 0x0152 + when 0xBD; array_enc << 0x0153 + when 0xBE; array_enc << 0x0178 + else + array_enc << num + end + end + array_enc.pack('U*') + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/SHIFT-JIS.rb b/vendor/plugins/rexml/lib/rexml/encodings/SHIFT-JIS.rb new file mode 100644 index 00000000..93c7877a --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/SHIFT-JIS.rb @@ -0,0 +1,37 @@ +module REXML + module Encoding + begin + require 'uconv' + + def decode_sjis content + Uconv::sjistou8(content) + end + + def encode_sjis(str) + Uconv::u8tosjis(str) + end + rescue LoadError + require 'nkf' + + SJISTOU8 = '-Swm0' + U8TOSJIS = '-Wsm0' + + def decode_sjis(str) + NKF.nkf(SJISTOU8, str) + end + + def encode_sjis content + NKF.nkf(U8TOSJIS, content) + end + end + + b = proc do |obj| + class << obj + alias decode decode_sjis + alias encode encode_sjis + end + end + register("SHIFT-JIS", &b) + register("SHIFT_JIS", &b) + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/SHIFT_JIS.rb b/vendor/plugins/rexml/lib/rexml/encodings/SHIFT_JIS.rb new file mode 100644 index 00000000..e355704a --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/SHIFT_JIS.rb @@ -0,0 +1 @@ +require 'rexml/encodings/SHIFT-JIS' diff --git a/vendor/plugins/rexml/lib/rexml/encodings/UNILE.rb b/vendor/plugins/rexml/lib/rexml/encodings/UNILE.rb new file mode 100644 index 00000000..d054140c --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/UNILE.rb @@ -0,0 +1,34 @@ +module REXML + module Encoding + def encode_unile content + array_utf8 = content.unpack("U*") + array_enc = [] + array_utf8.each do |num| + if ((num>>16) > 0) + array_enc << ?? + array_enc << 0 + else + array_enc << (num & 0xFF) + array_enc << (num >> 8) + end + end + array_enc.pack('C*') + end + + def decode_unile(str) + array_enc=str.unpack('C*') + array_utf8 = [] + 0.step(array_enc.size-1, 2){|i| + array_utf8 << (array_enc.at(i) + array_enc.at(i+1)*0x100) + } + array_utf8.pack('U*') + end + + register(UNILE) do |obj| + class << obj + alias decode decode_unile + alias encode encode_unile + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/US-ASCII.rb b/vendor/plugins/rexml/lib/rexml/encodings/US-ASCII.rb new file mode 100644 index 00000000..fb4c2170 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/US-ASCII.rb @@ -0,0 +1,30 @@ +module REXML + module Encoding + # Convert from UTF-8 + def encode_ascii content + array_utf8 = content.unpack('U*') + array_enc = [] + array_utf8.each do |num| + if num <= 0x7F + array_enc << num + else + # Numeric entity (&#nnnn;); shard by Stefan Scholl + array_enc.concat "&\##{num};".unpack('C*') + end + end + array_enc.pack('C*') + end + + # Convert to UTF-8 + def decode_ascii(str) + str.unpack('C*').pack('U*') + end + + register("US-ASCII") do |obj| + class << obj + alias decode decode_ascii + alias encode encode_ascii + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/UTF-16.rb b/vendor/plugins/rexml/lib/rexml/encodings/UTF-16.rb new file mode 100644 index 00000000..007c493d --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/UTF-16.rb @@ -0,0 +1,35 @@ +module REXML + module Encoding + def encode_utf16 content + array_utf8 = content.unpack("U*") + array_enc = [] + array_utf8.each do |num| + if ((num>>16) > 0) + array_enc << 0 + array_enc << ?? + else + array_enc << (num >> 8) + array_enc << (num & 0xFF) + end + end + array_enc.pack('C*') + end + + def decode_utf16(str) + str = str[2..-1] if /^\376\377/n =~ str + array_enc=str.unpack('C*') + array_utf8 = [] + 0.step(array_enc.size-1, 2){|i| + array_utf8 << (array_enc.at(i+1) + array_enc.at(i)*0x100) + } + array_utf8.pack('U*') + end + + register(UTF_16) do |obj| + class << obj + alias decode decode_utf16 + alias encode encode_utf16 + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/encodings/UTF-8.rb b/vendor/plugins/rexml/lib/rexml/encodings/UTF-8.rb new file mode 100644 index 00000000..bb08f441 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/encodings/UTF-8.rb @@ -0,0 +1,18 @@ +module REXML + module Encoding + def encode_utf8 content + content + end + + def decode_utf8(str) + str + end + + register(UTF_8) do |obj| + class << obj + alias decode decode_utf8 + alias encode encode_utf8 + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/entity.rb b/vendor/plugins/rexml/lib/rexml/entity.rb new file mode 100644 index 00000000..1c6a25c4 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/entity.rb @@ -0,0 +1,165 @@ +require 'rexml/child' +require 'rexml/source' +require 'rexml/xmltokens' + +module REXML + # God, I hate DTDs. I really do. Why this idiot standard still + # plagues us is beyond me. + 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 = "" + GEDECL = "" + 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 definiton, 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. The best thing to do is + # dump the stupid DTDs and use XMLSchema instead. + # + # 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 matchs 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 + 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 << to which the entity will be + # output + # indent:: + # *DEPRECATED* and ignored + def write out, indent=-1 + 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: + # + # + # then: + # doctype.entity('yada').value #-> "nanoo bar nanoo" + def value + if @value + matches = @value.scan(PEREFERENCE_RE) + rv = @value.clone + if @parent + matches.each do |entity_reference| + entity_value = @parent.entity( entity_reference[0] ) + 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+. + module EntityConst + # +>+ + GT = Entity.new( 'gt', '>' ) + # +<+ + LT = Entity.new( 'lt', '<' ) + # +&+ + AMP = Entity.new( 'amp', '&' ) + # +"+ + QUOT = Entity.new( 'quot', '"' ) + # +'+ + APOS = Entity.new( 'apos', "'" ) + end +end diff --git a/vendor/plugins/rexml/lib/rexml/formatters/default.rb b/vendor/plugins/rexml/lib/rexml/formatters/default.rb new file mode 100644 index 00000000..b4d63bc5 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/formatters/default.rb @@ -0,0 +1,109 @@ +module REXML + module Formatters + class Default + # Prints out the XML document with no formatting -- except if id_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 <<. 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.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 << "" + 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.sub(/\\/u, '') + output << node.target + output << ' ' + output << node.content + output << Instruction::STOP.sub(/\\/u, '') + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/formatters/pretty.rb b/vendor/plugins/rexml/lib/rexml/formatters/pretty.rb new file mode 100644 index 00000000..3666eddc --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/formatters/pretty.rb @@ -0,0 +1,138 @@ +require 'rexml/formatters/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 feeble 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 << "" + end + + def write_text( node, output ) + s = node.to_s() + s.gsub!(/\s/,' ') + s.squeeze!(" ") + s = wrap(s, 80-@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) + # Recursivly wrap string at width. + return string if string.length <= width + place = string.rindex(' ', width) # Position in string with last ' ' before cutoff + return string[0,place] + "\n" + wrap(string[place+1..-1], width) + end + + end + end +end + diff --git a/vendor/plugins/rexml/lib/rexml/formatters/transitive.rb b/vendor/plugins/rexml/lib/rexml/formatters/transitive.rb new file mode 100644 index 00000000..1d80f21f --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/formatters/transitive.rb @@ -0,0 +1,56 @@ +require 'rexml/formatters/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 ) + @indentation = indentation + @level = 0 + 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 << "/" + 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 + @level += @indentation + node.children.each { |child| + write( child, output ) + } + @level -= @indentation + output << "" + end + + def write_text( node, output ) + output << node.to_s() + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/functions.rb b/vendor/plugins/rexml/lib/rexml/functions.rb new file mode 100644 index 00000000..b3c89877 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/functions.rb @@ -0,0 +1,388 @@ +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 + @@context = nil + @@namespace_context = {} + @@variables = {} + + 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 + + def Functions::last( ) + @@context[:size] + end + + def Functions::position( ) + @@context[:index] + end + + 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 + + # UNTESTED + 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 defined? @@context[:node].namespace + else + if node_set.respond_to? :each + node_set.each { |node| yield node if defined? node.namespace } + 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=nil ) + #object = @context unless object + if object.instance_of? Array + string( object[0] ) + elsif defined? object.node_type + if object.node_type == :attribute + object.value + elsif object.node_type == :element || object.node_type == :document + string_value(object) + else + object.to_s + end + elsif object.nil? + return "" + else + object.to_s + end + end + + 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 + + # UNTESTED + def Functions::concat( *objects ) + objects.join + 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) + test_string = string(test) + 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 = ruby_start.round - 1 + ruby_length = ruby_length.round + + 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 charactcer 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 + + # UNTESTED + def Functions::boolean( object=nil ) + if object.kind_of? String + if object =~ /\d+/u + return object.to_f != 0 + else + return object.size > 0 + end + elsif object.kind_of? Array + object = object.find{|x| x and true} + end + return object ? true : false + 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=nil ) + object = @@context[:node] unless object + case object + when true + Float(1) + when false + Float(0) + when Array + number(string( object )) + when Numeric + object.to_f + else + str = string( object ) + # If XPath ever gets scientific notation... + #if str =~ /^\s*-?(\d*\.?\d+|\d+\.)([Ee]\d*)?\s*$/ + if str =~ /^\s*-?(\d*\.?\d+|\d+\.)\s*$/ + str.to_f + else + (0.0 / 0.0) + 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 ) + begin + number(number).round + rescue FloatDomainError + number(number) + end + end + + def Functions::processing_instruction( node ) + node.node_type == :processing_instruction + end + + def Functions::method_missing( id ) + puts "METHOD MISSING #{id.id2name}" + XPath.match( @@context[:node], id.id2name ) + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/instruction.rb b/vendor/plugins/rexml/lib/rexml/instruction.rb new file mode 100644 index 00000000..c16b894b --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/instruction.rb @@ -0,0 +1,70 @@ +require "rexml/child" +require "rexml/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 + # 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). If a Source, then the source is scanned and parsed for + # an Instruction declaration. + # @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) + if target.kind_of? String + super() + @target = target + @content = content + elsif target.kind_of? Instruction + super(content) + @target = target.target + @content = target.content + 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" ) + indent(writer, indent) + writer << START.sub(/\\/u, '') + writer << @target + writer << ' ' + writer << @content + writer << STOP.sub(/\\/u, '') + 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 + "" + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/light/node.rb b/vendor/plugins/rexml/lib/rexml/light/node.rb new file mode 100644 index 00000000..943ec5f1 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/light/node.rb @@ -0,0 +1,196 @@ +require 'rexml/xmltokens' +require 'rexml/light/node' + +# [ :element, parent, name, attributes, children* ] + # a = Node.new + # a << "B" # => B + # a.b # => B + # a.b[1] # => B + # a.b[1]["x"] = "y" # => B + # a.b[0].c # => B + # a.b.c << "D" # => BD +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( &block ) + 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 diff --git a/vendor/plugins/rexml/lib/rexml/namespace.rb b/vendor/plugins/rexml/lib/rexml/namespace.rb new file mode 100644 index 00000000..3e879058 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/namespace.rb @@ -0,0 +1,47 @@ +require 'rexml/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 + name =~ NAMESPLIT + if $1 + @prefix = $1 + else + @prefix = "" + @namespace = "" + end + @name = $2 + 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 diff --git a/vendor/plugins/rexml/lib/rexml/node.rb b/vendor/plugins/rexml/lib/rexml/node.rb new file mode 100644 index 00000000..d5e8456e --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/node.rb @@ -0,0 +1,75 @@ +require "rexml/parseexception" +require "rexml/formatters/pretty" +require "rexml/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" ) + 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 diff --git a/vendor/plugins/rexml/lib/rexml/output.rb b/vendor/plugins/rexml/lib/rexml/output.rb new file mode 100644 index 00000000..be4d23d4 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/output.rb @@ -0,0 +1,24 @@ +require 'rexml/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 = encd == UTF_8 ? false : true + end + + def <<( content ) + @output << (@to_utf ? self.encode(content) : content) + end + + def to_s + "Output[#{encoding}]" + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/parent.rb b/vendor/plugins/rexml/lib/rexml/parent.rb new file mode 100644 index 00000000..a20aaaef --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parent.rb @@ -0,0 +1,166 @@ +require "rexml/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 ) + #puts "PARENT GOTS #{size} CHILDREN" + object.parent = self + @children << object + #puts "PARENT NOW GOTS #{size} CHILDREN" + 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 + 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 diff --git a/vendor/plugins/rexml/lib/rexml/parseexception.rb b/vendor/plugins/rexml/lib/rexml/parseexception.rb new file mode 100644 index 00000000..feb7a7e6 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parseexception.rb @@ -0,0 +1,51 @@ +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].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 diff --git a/vendor/plugins/rexml/lib/rexml/parsers/baseparser.rb b/vendor/plugins/rexml/lib/rexml/parsers/baseparser.rb new file mode 100644 index 00000000..85f2c4e4 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parsers/baseparser.rb @@ -0,0 +1,530 @@ +require 'rexml/parseexception' +require 'rexml/undefinednamespaceexception' +require 'rexml/source' +require 'set' + +module REXML + module Parsers + # = Using the Pull Parser + # This API is experimental, and subject to change. + # parser = PullParser.new( "texttxet" ) + # 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( "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 + if String.method_defined? :encode + # Oniguruma / POSIX [understands unicode] + LETTER = '[[:alpha:]]' + DIGIT = '[[:digit:]]' + else + # Ruby < 1.9 [doesn't understand unicode] + LETTER = 'a-zA-Z' + DIGIT = '\d' + end + + COMBININGCHAR = '' # TODO + EXTENDER = '' # TODO + + NCNAME_STR= "[#{LETTER}_:][-#{LETTER}#{DIGIT}._:#{COMBININGCHAR}#{EXTENDER}]*" + NAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})" + UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" + + NAMECHAR = '[\-\w\d\.:]' + NAME = "([\\w:]#{NAMECHAR}*)" + NMTOKEN = "(?:#{NAMECHAR})+" + NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*" + REFERENCE = "&(?:#{NAME};|#\\d+;|#x[0-9a-fA-F]+;)" + REFERENCE_RE = /#{REFERENCE}/ + + DOCTYPE_START = /\A\s*)/um + ATTRIBUTE_PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\4/um + COMMENT_START = /\A/um + CDATA_START = /\A/um + CDATA_PATTERN = //um + XMLDECL_START = /\A<\?xml\s/u; + XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um + INSTRUCTION_START = /\A<\?/u + INSTRUCTION_PATTERN = /<\?(.*?)(\s+.*?)?\?>/um + TAG_MATCH = /^<((?>#{NAME_STR}))\s*((?>\s+#{UNAME_STR}\s*=\s*(["']).*?\5)*)\s*(\/)?>/um + CLOSE_MATCH = /^\s*<\/(#{NAME_STR})\s*>/um + + VERSION = /\bversion\s*=\s*["'](.*?)['"]/um + ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um + STANDALONE = /\bstandalone\s*=\s["'](.*?)['"]/um + + ENTITY_START = /^\s*/um + SYSTEMENTITY = /^\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 = /^\s*/um + NOTATIONDECL_START = /^\s*/um + SYSTEM = /^\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 = "" + GEDECL = "" + ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um + + EREFERENCE = /&(?!#{NAME};)/ + + DEFAULT_ENTITIES = { + 'gt' => [/>/, '>', '>', />/], + 'lt' => [/</, '<', '<', / [/"/, '"', '"', /"/], + "apos" => [/'/, "'", "'", /'/] + } + + + ###################################################################### + # These are patterns to identify common markup errors, to make the + # error messages more informative. + ###################################################################### + MISSING_ATTRIBUTE_QUOTES = /^<#{NAME_STR}\s+#{NAME_STR}\s*=\s*[^"']/um + + def initialize( source ) + self.stream = source + end + + def add_listener( listener ) + if !defined?(@listeners) or !@listeners + @listeners = [] + instance_eval <<-EOL + alias :_old_pull :pull + def pull + event = _old_pull + @listeners.each do |listener| + listener.receive event + end + event + end + EOL + end + @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 + 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? + @source.encoding = encoding + standalone = STANDALONE.match(results) + standalone = standalone[1] unless standalone.nil? + return [ :xmldecl, version, encoding, standalone ] + when INSTRUCTION_START + return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ] + 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" + if @source.buffer.respond_to? :force_encoding + @source.buffer.force_encoding(Encoding::UTF_8) + end + 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 is [ :entity, name, PUBLIC, pubid, href ] + 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 CDATA_END + @document_status = :after_doctype + @source.match( CDATA_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_to_consume( '>', CLOSE_MATCH) + md = @source.match( CLOSE_MATCH, true ) + raise REXML::ParseException.new( "Missing end tag for "+ + "'#{last_tag}' (got \"#{md[1]}\")", + @source) unless last_tag == md[1] + 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 /--/, /-$/ + 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] == ?? + md = @source.match( INSTRUCTION_PATTERN, true ) + return [ :processing_instruction, md[1], md[2] ] if md + raise REXML::ParseException.new( "Bad instruction declaration", + @source) + else + # Get the next tag + md = @source.match(TAG_MATCH, true) + unless md + # Check for missing attribute quotes + raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES ) + raise REXML::ParseException.new("malformed XML: missing tag start", @source) + end + attributes = {} + prefixes = Set.new + prefixes << md[2] if md[2] + @nsstack.unshift(curr_ns=Set.new) + if md[4].size > 0 + attrs = md[4].scan( ATTRIBUTE_PATTERN ) + raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0 + attrs.each { |a,b,c,d,e| + if b == "xmlns" + if c == "xml" + if d != "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 c == "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 << c + elsif b + prefixes << b unless b == "xml" + end + + if attributes.has_key? a + msg = "Duplicate attribute #{a.inspect}" + raise REXML::ParseException.new( msg, @source, self) + end + + attributes[a] = e + } + end + + # 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 md[6] + @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 Exception, NameError => error + raise REXML::ParseException.new( "Exception parsing", + @source, self, (error ? error : $!) ) + end + return [ :dummy ] + end + + 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, '&' ) + entities.each do |key, value| + copy.gsub!( value, "&#{key};" ) unless entity_filter and + entity_filter.include?(entity) + end if entities + copy.gsub!( EREFERENCE, '&' ) + 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!( /�*((?:\d+)|(?:x[a-fA-F0-9]+));/ ) {|m| + 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!( /&/, '&' ) + end + rv + 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 diff --git a/vendor/plugins/rexml/lib/rexml/parsers/lightparser.rb b/vendor/plugins/rexml/lib/rexml/parsers/lightparser.rb new file mode 100644 index 00000000..0f350349 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parsers/lightparser.rb @@ -0,0 +1,60 @@ +require 'rexml/parsers/streamparser' +require 'rexml/parsers/baseparser' +require 'rexml/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 :end_doctype + context = context[1] + 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 diff --git a/vendor/plugins/rexml/lib/rexml/parsers/pullparser.rb b/vendor/plugins/rexml/lib/rexml/parsers/pullparser.rb new file mode 100644 index 00000000..36dc7160 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parsers/pullparser.rb @@ -0,0 +1,196 @@ +require 'forwardable' + +require 'rexml/parseexception' +require 'rexml/parsers/baseparser' +require 'rexml/xmltokens' + +module REXML + module Parsers + # = Using the Pull Parser + # This API is experimental, and subject to change. + # parser = PullParser.new( "texttxet" ) + # 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( "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 diff --git a/vendor/plugins/rexml/lib/rexml/parsers/sax2parser.rb b/vendor/plugins/rexml/lib/rexml/parsers/sax2parser.rb new file mode 100644 index 00000000..cafc3937 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parsers/sax2parser.rb @@ -0,0 +1,247 @@ +require 'rexml/parsers/baseparser' +require 'rexml/parseexception' +require 'rexml/namespace' +require 'rexml/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? + } + root = 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 + @entities[ event[1] ] = event[2] if event.size == 3 + handle( *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 + + # 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| + #puts sym.inspect+"=="+symbol.inspect+ "\t"+match.inspect+"=="+name.inspect+ "\t"+( (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)))).to_s + ( + (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 diff --git a/vendor/plugins/rexml/lib/rexml/parsers/streamparser.rb b/vendor/plugins/rexml/lib/rexml/parsers/streamparser.rb new file mode 100644 index 00000000..256d0f61 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parsers/streamparser.rb @@ -0,0 +1,46 @@ +module REXML + module Parsers + class StreamParser + def initialize source, listener + @listener = listener + @parser = BaseParser.new( source ) + 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 + return + when :start_element + 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] ) + 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] ) + end + end + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/parsers/treeparser.rb b/vendor/plugins/rexml/lib/rexml/parsers/treeparser.rb new file mode 100644 index 00000000..30327d0d --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parsers/treeparser.rb @@ -0,0 +1,100 @@ +require 'rexml/validation/validationexception' +require 'rexml/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 #{tag_stack.inspect}") + raise ParseException.new("No close tag for #{@build_context.xpath}") + 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::UndefinedNamespaceException + raise + rescue + raise ParseException.new( $!.message, @parser.source, @parser, $! ) + end + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/parsers/ultralightparser.rb b/vendor/plugins/rexml/lib/rexml/parsers/ultralightparser.rb new file mode 100644 index 00000000..adc4af18 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parsers/ultralightparser.rb @@ -0,0 +1,56 @@ +require 'rexml/parsers/streamparser' +require 'rexml/parsers/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, :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 diff --git a/vendor/plugins/rexml/lib/rexml/parsers/xpathparser.rb b/vendor/plugins/rexml/lib/rexml/parsers/xpathparser.rb new file mode 100644 index 00000000..15219885 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/parsers/xpathparser.rb @@ -0,0 +1,698 @@ +require 'rexml/namespace' +require 'rexml/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.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces + path.gsub!( /\s+([\]\)])/, '\1' ) + parsed = [] + path = 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 + #puts "LocationPath '#{path}'" + path = path.strip + 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 + #puts parsed.inspect + 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 + #puts "RelativeLocationPath #{path}" + while path.size > 0 + # (axis or @ or ) 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] == ?@ + #puts "ATTRIBUTE" + parsed << :attribute + path = path[1..-1] + # Goto Nodetest + elsif path =~ AXIS + parsed << $1.tr('-','_').intern + path = $' + # Goto Nodetest + else + parsed << :child + end + + #puts "NODETESTING '#{path}'" + n = [] + path = NodeTest( path, n) + #puts "NODETEST RETURNED '#{path}'" + + if path[0] == ?[ + path = Predicate( path, n ) + end + + parsed.concat(n) + end + + if path.size > 0 + if path[0] == ?/ + if path[1] == ?/ + parsed << :descendant_or_self + parsed << :node + path = path[2..-1] + else + path = path[1..-1] + end + else + return path + end + end + end + return path + 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 + # | NODE_TYPE '(' ')' NodeType + # | PI '(' LITERAL ')' PI + # | '[' expr ']' Predicate + NCNAMETEST= /^(#{NCNAME_STR}):\*/u + QNAME = Namespace::NAMESPLIT + NODE_TYPE = /^(comment|text|node)\(\s*\)/m + PI = /^processing-instruction\(/ + def NodeTest path, parsed + #puts "NodeTest with #{path}" + res = nil + case path + 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 NCNAMETEST + #puts "NCNAMETEST" + prefix = $1 + path = $' + parsed << :namespace + parsed << prefix + when QNAME + #puts "QNAME" + prefix = $1 + name = $2 + path = $' + prefix = "" unless prefix + parsed << :qname + parsed << prefix + parsed << name + end + return path + end + + # Filters the supplied nodeset on the predicate(s) + def Predicate path, parsed + #puts "PREDICATE with #{path}" + return nil unless path[0] == ?[ + predicates = [] + while path[0] == ?[ + path, expr = get_group(path) + predicates << expr[1..-2] if expr + end + #puts "PREDICATES = #{predicates.inspect}" + predicates.each{ |pred| + #puts "ORING #{pred}" + preds = [] + parsed << :predicate + parsed << preds + OrExpr(pred, preds) + } + #puts "PREDICATES = #{predicates.inspect}" + 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 + #puts "OR >>> #{path}" + n = [] + rest = AndExpr( path, n ) + #puts "OR <<< #{rest}" + 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 + #puts "AND >>> #{path}" + n = [] + rest = EqualityExpr( path, n ) + #puts "AND <<< #{rest}" + if rest != path + while rest =~ /^\s*( and )/ + n = [ :and, n, [] ] + #puts "AND >>> #{rest}" + rest = EqualityExpr( $', n[-1] ) + #puts "AND <<< #{rest}" + 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 + #puts "EQUALITY >>> #{path}" + n = [] + rest = RelationalExpr( path, n ) + #puts "EQUALITY <<< #{rest}" + 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 + #puts "RELATION >>> #{path}" + n = [] + rest = AdditiveExpr( path, n ) + #puts "RELATION <<< #{rest}" + 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 ('+' | S '-') MultiplicativeExpr + #| MultiplicativeExpr + def AdditiveExpr path, parsed + #puts "ADDITIVE >>> #{path}" + n = [] + rest = MultiplicativeExpr( path, n ) + #puts "ADDITIVE <<< #{rest}" + 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 + #puts "MULT >>> #{path}" + n = [] + rest = UnaryExpr( path, n ) + #puts "MULT <<< #{rest}" + 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 + + #puts "UNARY >>> #{path}" + n = [] + path = UnionExpr( path, n ) + #puts "UNARY <<< #{path}" + parsed.concat( n ) + path + end + + #| UnionExpr '|' PathExpr + #| PathExpr + def UnionExpr path, parsed + #puts "UNION >>> #{path}" + n = [] + rest = PathExpr( path, n ) + #puts "UNION <<< #{rest}" + 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 =~ /^\s*/ + path = $' + #puts "PATH >>> #{path}" + n = [] + rest = FilterExpr( path, n ) + #puts "PATH <<< '#{rest}'" + if rest != path + if rest and rest[0] == ?/ + return RelativeLocationPath(rest, n) + end + end + #puts "BEFORE WITH '#{rest}'" + rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w_*]/ + parsed.concat(n) + return rest + end + + #| FilterExpr Predicate + #| PrimaryExpr + def FilterExpr path, parsed + #puts "FILTER >>> #{path}" + n = [] + path = PrimaryExpr( path, n ) + #puts "FILTER <<< #{path}" + path = Predicate(path, n) if path and path[0] == ?[ + #puts "FILTER <<< #{path}" + 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 + arry = [] + case path + when VARIABLE_REFERENCE + varname = $1 + path = $' + parsed << :variable + parsed << varname + #arry << @variables[ varname ] + when /^(\w[-\w]*)(?:\()/ + #puts "PrimaryExpr :: Function >>> #$1 -- '#$''" + fname = $1 + tmp = $' + #puts "#{fname} =~ #{NT.inspect}" + return path if fname =~ NT + path = tmp + parsed << :function + parsed << fname + path = FunctionCall(path, parsed) + when NUMBER + #puts "LITERAL or NUMBER: #$1" + varname = $1.nil? ? $2 : $1 + path = $' + parsed << :literal + parsed << (varname.include?('.') ? varname.to_f : varname.to_i) + when LITERAL + #puts "LITERAL or NUMBER: #$1" + 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 diff --git a/vendor/plugins/rexml/lib/rexml/quickpath.rb b/vendor/plugins/rexml/lib/rexml/quickpath.rb new file mode 100644 index 00000000..c099db85 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/quickpath.rb @@ -0,0 +1,266 @@ +require 'rexml/functions' +require 'rexml/xmltokens' + +module REXML + class QuickPath + include Functions + include XMLTokens + + 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 + matches = [] + 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 + axe_name = $1 + rest = $' + 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 + + # 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!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/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 Fixnum + 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 Fixnum + 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 diff --git a/vendor/plugins/rexml/lib/rexml/rexml.rb b/vendor/plugins/rexml/lib/rexml/rexml.rb new file mode 100644 index 00000000..6ace202a --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/rexml.rb @@ -0,0 +1,31 @@ +# -*- encoding: utf-8 -*- +# 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 +# Version:: 3.1.7.2 +# Date:: 2007/275 +# +# 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-2007 Sean Russell " + DATE = "2007/275" + VERSION = "3.1.7.2" + REVISION = "$Revision: 1284 $".gsub(/\$Revision:|\$/,'').strip + + Copyright = COPYRIGHT + Version = VERSION +end diff --git a/vendor/plugins/rexml/lib/rexml/sax2listener.rb b/vendor/plugins/rexml/lib/rexml/sax2listener.rb new file mode 100644 index 00000000..8db1389d --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/sax2listener.rb @@ -0,0 +1,97 @@ +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, + # @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, 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 + # + def elementdecl content + end + # + # 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): + # + # ["%", "YN", "'\"Yes\"'", "\""] + # + # ["%", "YN", "'Yes'", "s"] + # + # ["WhatHeSaid", "\"He said %YN;\"", "YN"] + # + # ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] + # + # ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] + # + # ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"] + def entitydecl name, decl + end + # + def notationdecl content + end + # Called when is encountered in a document. + # @p content "..." + def cdata content + end + # Called when an XML PI is encountered in the document. + # EG: + # @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 diff --git a/vendor/plugins/rexml/lib/rexml/source.rb b/vendor/plugins/rexml/lib/rexml/source.rb new file mode 100644 index 00000000..42bfc7d0 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/source.rb @@ -0,0 +1,258 @@ +require 'rexml/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 + self.encoding = check_encoding( @buffer ) + end + @line = 0 + end + + + # Inherited from Encoding + # Overridden to support optimized en/decoding + def encoding=(enc) + return unless super + @line_break = encode( '>' ) + if enc != UTF_8 + @buffer = decode(@buffer) + @to_utf = true + else + @to_utf = false + if @buffer.respond_to? :force_encoding + @buffer.force_encoding Encoding::UTF_8 + end + end + 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 regexes 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 + 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 + + # Determining the encoding is a deceptively difficult issue to resolve. + # First, we check the first two bytes for UTF-16. Then we + # assume that the encoding is at least ASCII enough for the '>', and + # we read until we get one of those. This gives us the XML declaration, + # if there is one. If there isn't one, the file MUST be UTF-8, as per + # the XML spec. If there is one, we can determine the encoding from + # it. + @buffer = "" + str = @source.read( 2 ) + if encoding + self.encoding = encoding + elsif str[0,2] == "\xfe\xff" + @line_break = "\000>" + elsif str[0,2] == "\xff\xfe" + @line_break = ">\000" + elsif str[0,2] == "\xef\xbb" + str += @source.read(1) + str = '' if (str[2,1] == "\xBF") + @line_break = ">" + else + @line_break = ">" + end + super str+@source.readline( @line_break ) + 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 warrent duplicating + # some code + if rv.size == 0 + until @buffer =~ pattern or @source.nil? + begin + # READLINE OPT + #str = @source.read(@block_size) + str = @source.readline(@line_break) + str = decode(str) if @to_utf and str + @buffer << str + rescue Iconv::IllegalSequence + raise + rescue + @source = nil + end + end + rv = super + end + rv.taint + rv + end + + def read + begin + str = @source.readline(@line_break) + str = decode(str) if @to_utf and str + @buffer << str + if not @to_utf and @buffer.respond_to? :force_encoding + @buffer.force_encoding Encoding::UTF_8 + end + 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 + str = @source.readline(@line_break) + str = decode(str) if @to_utf and str + @buffer << str + rv = pattern.match(@buffer) + @buffer = $' if cons and rv + rescue + @source = nil + end + end + rv.taint + 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 + rescue IOError + pos = -1 + line = -1 + end + [pos, lineno, line] + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/streamlistener.rb b/vendor/plugins/rexml/lib/rexml/streamlistener.rb new file mode 100644 index 00000000..6f401125 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/streamlistener.rb @@ -0,0 +1,92 @@ +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, + # 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_end + # will be called immidiately 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: + # @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, + # @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, 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 + # + def elementdecl content + end + # + # 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): + # + # ["%", "YN", "'\"Yes\"'", "\""] + # + # ["%", "YN", "'Yes'", "s"] + # + # ["WhatHeSaid", "\"He said %YN;\"", "YN"] + # + # ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] + # + # ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""] + # + # ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"] + def entitydecl content + end + # + def notationdecl content + end + # Called when %foo; is encountered in a doctype declaration. + # @p content "foo" + def entity content + end + # Called when is encountered in a document. + # @p content "..." + def cdata content + end + # Called when an XML PI is encountered in the document. + # EG: + # @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 diff --git a/vendor/plugins/rexml/lib/rexml/syncenumerator.rb b/vendor/plugins/rexml/lib/rexml/syncenumerator.rb new file mode 100644 index 00000000..11609bdf --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/syncenumerator.rb @@ -0,0 +1,32 @@ +module REXML + class SyncEnumerator + include Enumerable + + # Creates a new SyncEnumerator which enumerates rows of given + # Enumerable objects. + def initialize(*enums) + @gens = enums + @length = @gens.collect {|x| x.size }.max + end + + # Returns the number of enumerated Enumerable objects, i.e. the size + # of each row. + def size + @gens.size + end + + # Returns the number of enumerated Enumerable objects, i.e. the size + # of each row. + def length + @gens.length + end + + # Enumerates rows of the Enumerable objects. + def each + @length.times {|i| + yield @gens.collect {|x| x[i]} + } + self + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/text.rb b/vendor/plugins/rexml/lib/rexml/text.rb new file mode 100644 index 00000000..c23cd17c --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/text.rb @@ -0,0 +1,403 @@ +require 'rexml/entity' +require 'rexml/doctype' +require 'rexml/child' +require 'rexml/doctype' +require 'rexml/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, /\r/u ] + SUBSTITUTES = ['&', '<', '>', '"', ''', ' '] + # Characters which are substituted in written strings + SLAICEPS = [ '<', '>', '"', "'", '&' ] + SETUTITSBUS = [ /</u, />/u, /"/u, /'/u, /&/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 = /�*((?:\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 Fixnum + [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 + )*$/x; + 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 ) #-> "<&" + # Text.new( "<&", false, nil, false ) #-> "&lt;&amp;" + # Text.new( "<&", false, nil, true ) #-> Parse exception + # Text.new( "<&", false, nil, true ) #-> "<&" + # # 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. + # + # +pattern+ INTERNAL USE ONLY + def initialize(arg, respect_whitespace=false, parent=nil, raw=nil, + entity_filter=nil, illegal=NEEDS_A_SECOND_CHECK ) + + @raw = false + + if parent + super( parent ) + @raw = parent.raw + else + @parent = nil + end + + @raw = raw unless raw.nil? + @entity_filter = entity_filter + @normalized = @unnormalized = nil + + if arg.kind_of? String + @string = arg.clone + @string.squeeze!(" \n\t") unless respect_whitespace + elsif arg.kind_of? Text + @string = arg.to_s + @raw = arg.raw + elsif + raise "Illegal argument of type #{arg.type} for Text constructor (#{arg})" + end + + @string.gsub!( /\r\n?/, "\n" ) + + Text.check(@string, NEEDS_A_SECOND_CHECK, doctype) if @raw and @parent + 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}\"" + end + end + else + string.scan(/[\x00-\x7F]|[\x80-\xBF][\xC0-\xF0]*|[\xC0-\xF0]/) do |c| + case c.unpack('U') + when *VALID_CHAR + else + raise "Illegal character #{c.inspect} in raw string \"#{string}\"" + end + end + end + end + + # context sensitive + string.scan(pattern).each do + if $1[-1] != ?; + raise "Illegal character '#{$1}' in raw string \"#{string}\"" + 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}' in raw string \"#{string}\"" + end + elsif $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) + end + + + # Appends text to this text node. The text is appended in the +raw+ mode + # of this text node. + def <<( to_append ) + @string << to_append.gsub( /\r\n?/, "\n" ) + 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 #-> "< & &s; russell" + # t = Text.new( "< & &s; russell", false, nil, false ) + # t.to_s #-> "< & &s; russell" + # u = Text.new( "sean russell", false, nil, true ) + # u.to_s #-> "sean russell" + def to_s + return @string if @raw + return @normalized if @normalized + + @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 + return @unnormalized if @unnormalized + @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" ) # foo + # e[0].value = "bar" # bar + # e[0].value = "" # <a> + def value=( val ) + @string = val.gsub( /\r\n?/, "\n" ) + @unnormalized = nil + @normalized = nil + @raw = false + end + + def wrap(string, width, addnewline=false) + # Recursivly 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| + 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") + 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 + + # 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!( /�*((?:\d+)|(?:x[a-f0-9]+));/ ) {|m| + 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, '&' ) + copy = copy.gsub( "&", "&" ) + 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) ) + 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 ) + string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) { |ref| + 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 == '&' + '&' + 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 diff --git a/vendor/plugins/rexml/lib/rexml/undefinednamespaceexception.rb b/vendor/plugins/rexml/lib/rexml/undefinednamespaceexception.rb new file mode 100644 index 00000000..8ebfdfd0 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/undefinednamespaceexception.rb @@ -0,0 +1,8 @@ +require 'rexml/parseexception' +module REXML + class UndefinedNamespaceException < ParseException + def initialize( prefix, source, parser ) + super( "Undefined prefix #{prefix} found" ) + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/validation/relaxng.rb b/vendor/plugins/rexml/lib/rexml/validation/relaxng.rb new file mode 100644 index 00000000..969f51bc --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/validation/relaxng.rb @@ -0,0 +1,559 @@ +require "rexml/validation/validation" +require "rexml/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}. " + #puts "Next (#@current) is #{@events[@current]}" + #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 + #puts "Current isn't a state" + if ( @events[@current].matches?(event) ) + @current += 1 + if @events[@current].nil? + #puts "#{inspect[0,5]} 1RETURNING #{@previous.inspect[0,5]}" + return @previous.pop + elsif @events[@current].kind_of? State + @current += 1 + #puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}" + @events[@current-1].previous = self + return @events[@current-1] + else + #puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}" + 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 + #puts "In next with #{event.inspect}." + #puts "events is #{@events.inspect}" + unless @events + @events = [] + return nil + end + #puts "current = #@current" + 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 + #puts "IN CHOICE EXPECTED" + #puts "EVENTS = #{@events.inspect}" + 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 + + #puts "In next with #{event.inspect}." + #puts "events is #{@events.inspect}" + @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 + #puts "In next with #{event.inspect}." + #puts "Next (#@current) is #{@events[@current]}" + if ( @events[@current].kind_of? State ) + @current += 1 + @events[@current-1].previous = self + return @events[@current-1].next( event ) + end + #puts "Current isn't a state" + return @previous.pop.next( event ) if @events[@current].nil? + if ( @events[@current].matches?(event) ) + @current += 1 + if @events[@current].nil? + #puts "#{inspect[0,5]} 1RETURNING self" unless @choices[@choice].nil? + return self unless @choices[@choice].nil? + #puts "#{inspect[0,5]} 1RETURNING #{@previous[-1].inspect[0,5]}" + return @previous.pop + elsif @events[@current].kind_of? State + @current += 1 + #puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}" + @events[@current-1].previous = self + return @events[@current-1] + else + #puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}" + 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 + #puts "IN CHOICE EXPECTED" + #puts "EVENTS = #{@events.inspect}" + 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 diff --git a/vendor/plugins/rexml/lib/rexml/validation/validation.rb b/vendor/plugins/rexml/lib/rexml/validation/validation.rb new file mode 100644 index 00000000..93f5bfb3 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/validation/validation.rb @@ -0,0 +1,155 @@ +require 'rexml/validation/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 ) + #puts "Current: #@current" + #puts "Event: #{event.inspect}" + @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 + #puts "Checking attributes" + @attr_stack << event[2] + begin + sattr = [:start_attribute, nil] + eattr = [:end_attribute] + text = [:text, nil] + k,v = event[2].find { |key,value| + sattr[1] = key + #puts "Looking for #{sattr.inspect}" + m = @current.next( sattr ) + #puts "Got #{m.inspect}" + if m + # If the state has text children... + #puts "Looking for #{eattr.inspect}" + #puts "Expect #{m.expected}" + if m.matches?( eattr ) + #puts "Got end" + @current = m + else + #puts "Didn't get end" + text[1] = value + #puts "Looking for #{text.inspect}" + m = m.next( text ) + #puts "Got #{m.inspect}" + 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 ) + #puts "#@event_type =? #{event[0]} && #@event_arg =? #{event[1]} " + 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 diff --git a/vendor/plugins/rexml/lib/rexml/validation/validationexception.rb b/vendor/plugins/rexml/lib/rexml/validation/validationexception.rb new file mode 100644 index 00000000..4723d9e4 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/validation/validationexception.rb @@ -0,0 +1,9 @@ +module REXML + module Validation + class ValidationException < RuntimeError + def initialize msg + super + end + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/xmldecl.rb b/vendor/plugins/rexml/lib/rexml/xmldecl.rb new file mode 100644 index 00000000..427eb78c --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/xmldecl.rb @@ -0,0 +1,119 @@ +require 'rexml/encoding' +require 'rexml/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 + 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.sub(/\\/u, '') + if writer.kind_of? Output + writer << " #{content writer.encoding}" + else + writer << " #{content encoding}" + end + writer << STOP.sub(/\\/u, '') + 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.sub(/\\/u, '') + " ... " + STOP.sub(/\\/u, '') + end + + private + def content(enc) + rv = "version='#@version'" + rv << " encoding='#{enc}'" if @writeencoding || enc !~ /utf-8/i + rv << " standalone='#@standalone'" if @standalone + rv + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/xmltokens.rb b/vendor/plugins/rexml/lib/rexml/xmltokens.rb new file mode 100644 index 00000000..6bbe5b07 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/xmltokens.rb @@ -0,0 +1,18 @@ +module REXML + # Defines a number of tokens used for parsing XML. Not for general + # consumption. + module XMLTokens + NCNAME_STR= '[\w:][\-\w\d.]*' + NAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" + + NAMECHAR = '[\-\w\d\.:]' + NAME = "([\\w:]#{NAMECHAR}*)" + NMTOKEN = "(?:#{NAMECHAR})+" + 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 diff --git a/vendor/plugins/rexml/lib/rexml/xpath.rb b/vendor/plugins/rexml/lib/rexml/xpath.rb new file mode 100644 index 00000000..939399e2 --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/xpath.rb @@ -0,0 +1,66 @@ +require 'rexml/functions' +require 'rexml/xpath_parser' + +module REXML + # Wrapper class. Use this class to access the XPath functions. + class XPath + include Functions + 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. + # + # XPath.first( node ) + # XPath.first( doc, "//b"} ) + # XPath.first( node, "a/x:b", { "x"=>"http://doofus" } ) + def XPath::first element, path=nil, namespaces=nil, variables={} + 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 + parser.namespaces = namespaces + parser.variables = variables + path = "*" unless path + element = [element] unless element.kind_of? Array + parser.parse(path, element).flatten[0] + end + + # Itterates 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 + # + # XPath.each( node ) { |el| ... } + # XPath.each( node, '/*[@attr='v']' ) { |el| ... } + # XPath.each( node, 'ancestor::x' ) { |el| ... } + def XPath::each element, path=nil, namespaces=nil, variables={}, &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 + 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={} + parser = XPathParser.new + parser.namespaces = namespaces + parser.variables = variables + path = "*" unless path + element = [element] unless element.kind_of? Array + parser.parse(path,element) + end + end +end diff --git a/vendor/plugins/rexml/lib/rexml/xpath_parser.rb b/vendor/plugins/rexml/lib/rexml/xpath_parser.rb new file mode 100644 index 00000000..4275c2db --- /dev/null +++ b/vendor/plugins/rexml/lib/rexml/xpath_parser.rb @@ -0,0 +1,792 @@ +require 'rexml/namespace' +require 'rexml/xmltokens' +require 'rexml/attribute' +require 'rexml/syncenumerator' +require 'rexml/parsers/xpathparser' + +class Object + def dclone + clone + end +end +class Symbol + def dclone ; self ; end +end +class Fixnum + def dclone ; self ; end +end +class Float + def dclone ; self ; end +end +class Array + 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 + + def initialize( ) + @parser = REXML::Parsers::XPathParser.new + @namespaces = nil + @variables = {} + end + + def namespaces=( namespaces={} ) + Functions::namespace_context = namespaces + @namespaces = namespaces + end + + def variables=( vars={} ) + Functions::variables = vars + @variables = vars + end + + def parse path, nodeset + #puts "#"*40 + path_stack = @parser.parse( path ) + #puts "PARSE: #{path} => #{path_stack.inspect}" + #puts "PARSE: nodeset = #{nodeset.inspect}" + match( path_stack, nodeset ) + end + + def get_first path, nodeset + #puts "#"*40 + path_stack = @parser.parse( path ) + #puts "PARSE: #{path} => #{path_stack.inspect}" + #puts "PARSE: nodeset = #{nodeset.inspect}" + first( path_stack, nodeset ) + end + + def predicate path, nodeset + path_stack = @parser.parse( path ) + expr( 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 ) + #puts "#{depth}) Entering match( #{path.inspect}, #{tree.inspect} )" + 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 + #puts "#{depth}) CHILD checking #{name(c)}" + r = first( path[1..-1], c ) + #puts "#{depth}) RETURNING #{r.inspect}" if r + return r if r + end + when :qname + name = path[2] + #puts "#{depth}) QNAME #{name(tree)} == #{name} (path => #{path.size})" + if node.name == name + #puts "#{depth}) RETURNING #{tree.inspect}" if path.size == 3 + 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 ) + #puts "MATCH: path_stack = #{path_stack.inspect}" + #puts "MATCH: nodeset = #{nodeset.inspect}" + r = expr( path_stack, nodeset ) + #puts "MAIN EXPR => #{r.inspect}" + r + end + + private + + + # 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 + ALL = [ :attribute, :element, :text, :processing_instruction, :comment ] + ELEMENTS = [ :element ] + def expr( path_stack, nodeset, context=nil ) + #puts "#"*15 + #puts "In expr with #{path_stack.inspect}" + #puts "Returning" if path_stack.length == 0 || nodeset.length == 0 + node_types = ELEMENTS + return nodeset if path_stack.length == 0 || nodeset.length == 0 + while path_stack.length > 0 + #puts "#"*5 + #puts "Path stack = #{path_stack.inspect}" + #puts "Nodeset is #{nodeset.inspect}" + if nodeset.length == 0 + path_stack.clear + return [] + end + case (op = path_stack.shift) + when :document + nodeset = [ nodeset[0].root_node ] + #puts ":document, nodeset = #{nodeset.inspect}" + + when :qname + #puts "IN QNAME" + prefix = path_stack.shift + name = path_stack.shift + nodeset.delete_if do |node| + # FIXME: This DOUBLES the time XPath searches take + ns = get_namespace( node, prefix ) + #puts "NS = #{ns.inspect}" + #puts "node.node_type == :element => #{node.node_type == :element}" + if node.node_type == :element + #puts "node.name == #{name} => #{node.name == name}" + if node.name == name + #puts "node.namespace == #{ns.inspect} => #{node.namespace == ns}" + end + end + !(node.node_type == :element and + node.name == name and + node.namespace == ns ) + end + node_types = ELEMENTS + + when :any + #puts "ANY 1: nodeset = #{nodeset.inspect}" + #puts "ANY 1: node_types = #{node_types.inspect}" + nodeset.delete_if { |node| !node_types.include?(node.node_type) } + #puts "ANY 2: nodeset = #{nodeset.inspect}" + + when :self + # This space left intentionally blank + + when :processing_instruction + target = path_stack.shift + nodeset.delete_if do |node| + (node.node_type != :processing_instruction) or + ( target!='' and ( node.target != target ) ) + end + + when :text + nodeset.delete_if { |node| node.node_type != :text } + + when :comment + nodeset.delete_if { |node| node.node_type != :comment } + + when :node + # This space left intentionally blank + node_types = ALL + + when :child + new_nodeset = [] + nt = nil + nodeset.each do |node| + nt = node.node_type + new_nodeset += node.children if nt == :element or nt == :document + end + nodeset = new_nodeset + node_types = ELEMENTS + + when :literal + return path_stack.shift + + when :attribute + new_nodeset = [] + case path_stack.shift + when :qname + prefix = path_stack.shift + name = path_stack.shift + for element in nodeset + if element.node_type == :element + #puts "Element name = #{element.name}" + #puts "get_namespace( #{element.inspect}, #{prefix} ) = #{get_namespace(element, prefix)}" + attrib = element.attribute( name, get_namespace(element, prefix) ) + #puts "attrib = #{attrib.inspect}" + new_nodeset << attrib if attrib + end + end + when :any + #puts "ANY" + for element in nodeset + if element.node_type == :element + new_nodeset += element.attributes.to_a + end + end + end + nodeset = new_nodeset + + when :parent + #puts "PARENT 1: nodeset = #{nodeset}" + nodeset = nodeset.collect{|n| n.parent}.compact + #nodeset = expr(path_stack.dclone, nodeset.collect{|n| n.parent}.compact) + #puts "PARENT 2: nodeset = #{nodeset.inspect}" + node_types = ELEMENTS + + when :ancestor + new_nodeset = [] + nodeset.each do |node| + while node.parent + node = node.parent + new_nodeset << node unless new_nodeset.include? node + end + end + nodeset = new_nodeset + node_types = ELEMENTS + + when :ancestor_or_self + new_nodeset = [] + nodeset.each do |node| + if node.node_type == :element + new_nodeset << node + while ( node.parent ) + node = node.parent + new_nodeset << node unless new_nodeset.include? node + end + end + end + nodeset = new_nodeset + node_types = ELEMENTS + + when :predicate + new_nodeset = [] + subcontext = { :size => nodeset.size } + pred = path_stack.shift + nodeset.each_with_index { |node, index| + subcontext[ :node ] = node + #puts "PREDICATE SETTING CONTEXT INDEX TO #{index+1}" + subcontext[ :index ] = index+1 + pc = pred.dclone + #puts "#{node.hash}) Recursing with #{pred.inspect} and [#{node.inspect}]" + result = expr( pc, [node], subcontext ) + result = result[0] if result.kind_of? Array and result.length == 1 + #puts "#{node.hash}) Result = #{result.inspect} (#{result.class.name})" + if result.kind_of? Numeric + #puts "Adding node #{node.inspect}" if result == (index+1) + new_nodeset << node if result == (index+1) + elsif result.instance_of? Array + if result.size > 0 and result.inject(false) {|k,s| s or k} + #puts "Adding node #{node.inspect}" if result.size > 0 + new_nodeset << node if result.size > 0 + end + else + #puts "Adding node #{node.inspect}" if result + new_nodeset << node if result + end + } + #puts "New nodeset = #{new_nodeset.inspect}" + #puts "Path_stack = #{path_stack.inspect}" + nodeset = new_nodeset +=begin + predicate = path_stack.shift + ns = nodeset.clone + result = expr( predicate, ns ) + #puts "Result = #{result.inspect} (#{result.class.name})" + #puts "nodeset = #{nodeset.inspect}" + if result.kind_of? Array + nodeset = result.zip(ns).collect{|m,n| n if m}.compact + else + nodeset = result ? nodeset : [] + end + #puts "Outgoing NS = #{nodeset.inspect}" +=end + + when :descendant_or_self + rv = descendant_or_self( path_stack, nodeset ) + path_stack.clear + nodeset = rv + node_types = ELEMENTS + + when :descendant + results = [] + nt = nil + nodeset.each do |node| + nt = node.node_type + results += expr( path_stack.dclone.unshift( :descendant_or_self ), + node.children ) if nt == :element or nt == :document + end + nodeset = results + node_types = ELEMENTS + + when :following_sibling + #puts "FOLLOWING_SIBLING 1: nodeset = #{nodeset}" + results = [] + nodeset.each do |node| + next if node.parent.nil? + all_siblings = node.parent.children + current_index = all_siblings.index( node ) + following_siblings = all_siblings[ current_index+1 .. -1 ] + results += expr( path_stack.dclone, following_siblings ) + end + #puts "FOLLOWING_SIBLING 2: nodeset = #{nodeset}" + nodeset = results + + when :preceding_sibling + results = [] + nodeset.each do |node| + next if node.parent.nil? + all_siblings = node.parent.children + current_index = all_siblings.index( node ) + preceding_siblings = all_siblings[ 0, current_index ].reverse + results += preceding_siblings + end + nodeset = results + node_types = ELEMENTS + + when :preceding + new_nodeset = [] + nodeset.each do |node| + new_nodeset += preceding( node ) + end + #puts "NEW NODESET => #{new_nodeset.inspect}" + nodeset = new_nodeset + node_types = ELEMENTS + + when :following + new_nodeset = [] + nodeset.each do |node| + new_nodeset += following( node ) + end + nodeset = new_nodeset + node_types = ELEMENTS + + when :namespace + #puts "In :namespace" + new_nodeset = [] + prefix = path_stack.shift + nodeset.each do |node| + if (node.node_type == :element or node.node_type == :attribute) + if @namespaces + namespaces = @namespaces + elsif (node.node_type == :element) + namespaces = node.namespaces + else + namespaces = node.element.namesapces + end + #puts "Namespaces = #{namespaces.inspect}" + #puts "Prefix = #{prefix.inspect}" + #puts "Node.namespace = #{node.namespace}" + if (node.namespace == namespaces[prefix]) + new_nodeset << node + end + end + end + nodeset = new_nodeset + + when :variable + var_name = path_stack.shift + return @variables[ var_name ] + + # :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq + # TODO: Special case for :or and :and -- not evaluate the right + # operand if the left alone determines result (i.e. is true for + # :or and false for :and). + when :eq, :neq, :lt, :lteq, :gt, :gteq, :and, :or + left = expr( path_stack.shift, nodeset.dup, context ) + #puts "LEFT => #{left.inspect} (#{left.class.name})" + right = expr( path_stack.shift, nodeset.dup, context ) + #puts "RIGHT => #{right.inspect} (#{right.class.name})" + res = equality_relational_compare( left, op, right ) + #puts "RES => #{res.inspect}" + return res + + when :and + left = expr( path_stack.shift, nodeset.dup, context ) + #puts "LEFT => #{left.inspect} (#{left.class.name})" + if left == false || left.nil? || !left.inject(false) {|a,b| a | b} + return [] + end + right = expr( path_stack.shift, nodeset.dup, context ) + #puts "RIGHT => #{right.inspect} (#{right.class.name})" + res = equality_relational_compare( left, op, right ) + #puts "RES => #{res.inspect}" + return res + + when :div + left = Functions::number(expr(path_stack.shift, nodeset, context)).to_f + right = Functions::number(expr(path_stack.shift, nodeset, context)).to_f + return (left / right) + + when :mod + left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f + right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f + return (left % right) + + when :mult + left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f + right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f + return (left * right) + + when :plus + left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f + right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f + return (left + right) + + when :minus + left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f + right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f + return (left - right) + + when :union + left = expr( path_stack.shift, nodeset, context ) + right = expr( path_stack.shift, nodeset, context ) + return (left | right) + + when :neg + res = expr( path_stack, nodeset, context ) + return -(res.to_f) + + when :not + when :function + func_name = path_stack.shift.tr('-','_') + arguments = path_stack.shift + #puts "FUNCTION 0: #{func_name}(#{arguments.collect{|a|a.inspect}.join(', ')})" + subcontext = context ? nil : { :size => nodeset.size } + + res = [] + cont = context + nodeset.each_with_index { |n, i| + if subcontext + subcontext[:node] = n + subcontext[:index] = i + cont = subcontext + end + arg_clone = arguments.dclone + args = arg_clone.collect { |arg| + #puts "FUNCTION 1: Calling expr( #{arg.inspect}, [#{n.inspect}] )" + expr( arg, [n], cont ) + } + #puts "FUNCTION 2: #{func_name}(#{args.collect{|a|a.inspect}.join(', ')})" + Functions.context = cont + res << Functions.send( func_name, *args ) + #puts "FUNCTION 3: #{res[-1].inspect}" + } + return res + + end + end # while + #puts "EXPR returning #{nodeset.inspect}" + return nodeset + end + + + ########################################################## + # FIXME + # The next two methods are BAD MOJO! + # This is my achilles heel. If anybody thinks of a better + # way of doing this, be my guest. This really sucks, but + # it is a wonder it works at all. + # ######################################################## + + def descendant_or_self( path_stack, nodeset ) + rs = [] + #puts "#"*80 + #puts "PATH_STACK = #{path_stack.inspect}" + #puts "NODESET = #{nodeset.collect{|n|n.inspect}.inspect}" + d_o_s( path_stack, nodeset, rs ) + #puts "RS = #{rs.collect{|n|n.inspect}.inspect}" + document_order(rs.flatten.compact) + #rs.flatten.compact + end + + def d_o_s( p, ns, r ) + #puts "IN DOS with #{ns.inspect}; ALREADY HAVE #{r.inspect}" + nt = nil + ns.each_index do |i| + n = ns[i] + #puts "P => #{p.inspect}" + x = expr( p.dclone, [ n ] ) + nt = n.node_type + d_o_s( p, n.children, x ) if nt == :element or nt == :document and n.children.size > 0 + r.concat(x) if x.size > 0 + end + 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 document_order( array_of_nodes ) + 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 ] + } + #puts "new_arry = #{new_arry.inspect}" + new_arry.sort{ |s1, s2| s1[0] <=> s2[0] }.collect{ |s| s[1] } + end + + + def recurse( nodeset, &block ) + for node in nodeset + yield node + recurse( node, &block ) if node.node_type == :element + 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 ) + #puts "IN PRECEDING" + ancestors = [] + p = node.parent + while p + ancestors << p + p = p.parent + end + + acc = [] + p = preceding_node_of( node ) + #puts "P = #{p.inspect}" + while p + if ancestors.include? p + ancestors.delete(p) + else + acc << p + end + p = preceding_node_of( p ) + #puts "P = #{p.inspect}" + end + acc + end + + def preceding_node_of( node ) + #puts "NODE: #{node.inspect}" + #puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}" + #puts "PARENT NODE: #{node.parent}" + 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 ) + #puts "IN PRECEDING" + acc = [] + p = next_sibling_node( node ) + #puts "P = #{p.inspect}" + while p + acc << p + p = following_node_of( p ) + #puts "P = #{p.inspect}" + end + acc + end + + def following_node_of( node ) + #puts "NODE: #{node.inspect}" + #puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}" + #puts "PARENT NODE: #{node.parent}" + 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 + #puts "psn = #{psn.inspect}" + end + return psn + end + + def norm b + case b + when true, false + return b + when 'true', 'false' + return Functions::boolean( b ) + when /^\d+(\.\d+)?$/ + return Functions::number( b ) + else + return Functions::string( b ) + end + end + + def equality_relational_compare( set1, op, set2 ) + #puts "EQ_REL_COMP(#{set1.inspect} #{op.inspect} #{set2.inspect})" + if set1.kind_of? Array and set2.kind_of? Array + #puts "#{set1.size} & #{set2.size}" + if set1.size == 1 and set2.size == 1 + set1 = set1[0] + set2 = set2[0] + elsif set1.size == 0 or set2.size == 0 + nd = set1.size==0 ? set2 : set1 + rv = nd.collect { |il| compare( il, op, nil ) } + #puts "RV = #{rv.inspect}" + return rv + else + res = [] + enum = SyncEnumerator.new( set1, set2 ).each { |i1, i2| + #puts "i1 = #{i1.inspect} (#{i1.class.name})" + #puts "i2 = #{i2.inspect} (#{i2.class.name})" + i1 = norm( i1 ) + i2 = norm( i2 ) + res << compare( i1, op, i2 ) + } + return res + end + end + #puts "EQ_REL_COMP: #{set1.inspect} (#{set1.class.name}), #{op}, #{set2.inspect} (#{set2.class.name})" + #puts "COMPARING VALUES" + # 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 or set2.kind_of? Array + #puts "ISA ARRAY" + if set1.kind_of? Array + a = set1 + b = set2 + else + a = set2 + b = set1 + end + + case b + when true, false + return a.collect {|v| compare( Functions::boolean(v), op, b ) } + when Numeric + return a.collect {|v| compare( Functions::number(v), op, b )} + when /^\d+(\.\d+)?$/ + b = Functions::number( b ) + #puts "B = #{b.inspect}" + return a.collect {|v| compare( Functions::number(v), op, b )} + else + #puts "Functions::string( #{b}(#{b.class.name}) ) = #{Functions::string(b)}" + b = Functions::string( b ) + return a.collect { |v| compare( Functions::string(v), op, b ) } + 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 + s1 = set1.to_s + s2 = set2.to_s + #puts "EQ_REL_COMP: #{set1}=>#{s1}, #{set2}=>#{s2}" + if s1 == 'true' or s1 == 'false' or s2 == 'true' or s2 == 'false' + #puts "Functions::boolean(#{set1})=>#{Functions::boolean(set1)}" + #puts "Functions::boolean(#{set2})=>#{Functions::boolean(set2)}" + set1 = Functions::boolean( set1 ) + set2 = Functions::boolean( set2 ) + else + if op == :eq or op == :neq + if s1 =~ /^\d+(\.\d+)?$/ or s2 =~ /^\d+(\.\d+)?$/ + set1 = Functions::number( s1 ) + set2 = Functions::number( s2 ) + else + set1 = Functions::string( set1 ) + set2 = Functions::string( set2 ) + end + else + set1 = Functions::number( set1 ) + set2 = Functions::number( set2 ) + end + end + #puts "EQ_REL_COMP: #{set1} #{op} #{set2}" + #puts ">>> #{compare( set1, op, set2 )}" + return compare( set1, op, set2 ) + end + return false + end + + def compare a, op, b + #puts "COMPARE #{a.inspect}(#{a.class.name}) #{op} #{b.inspect}(#{b.class.name})" + case op + when :eq + a == b + when :neq + a != b + when :lt + a < b + when :lteq + a <= b + when :gt + a > b + when :gteq + a >= b + when :and + a and b + when :or + a or b + else + false + end + end + end +end