1 require "booh/rexml/element"
2 require "booh/rexml/xmldecl"
3 require "booh/rexml/source"
4 require "booh/rexml/comment"
5 require "booh/rexml/doctype"
6 require "booh/rexml/instruction"
7 require "booh/rexml/rexml"
8 require "booh/rexml/parseexception"
9 require "booh/rexml/output"
10 require "booh/rexml/parsers/baseparser"
11 require "booh/rexml/parsers/streamparser"
12 require "booh/rexml/parsers/treeparser"
15 # Represents a full XML document, including PIs, a doctype, etc. A
16 # Document has a single child that can be accessed by root().
17 # Note that if you want to have an XML declaration written for a document
18 # you create, you must add one; REXML documents do not write a default
19 # declaration for you. See |DECLARATION| and |write|.
20 class Document < Element
21 # A convenient default XML declaration. If you want an XML declaration,
22 # the easiest way to add one is mydoc << Document::DECLARATION
24 # Use: mydoc << XMLDecl.default
25 DECLARATION = XMLDecl.default
28 # @param source if supplied, must be a Document, String, or IO.
29 # Documents have their context and Element attributes cloned.
30 # Strings are expected to be valid XML documents. IOs are expected
31 # to be sources of valid XML documents.
32 # @param context if supplied, contains the context of the document;
33 # this should be a Hash.
34 # NOTE that I'm not sure what the context is for; I cloned it out of
35 # the Electric XML API (in which it also seems to do nothing), and it
36 # is now legacy. It may do something, someday... it may disappear.
37 def initialize( source = nil, context = {} )
41 if source.kind_of? Document
42 @context = source.context
58 # According to the XML spec, a root node has no expanded name
62 #d ? d.name : "UNDEFINED"
65 alias :name :expanded_name
67 # We override this, because XMLDecls and DocTypes must go at the start
70 if child.kind_of? XMLDecl
71 @children.unshift child
72 elsif child.kind_of? DocType
73 # Find first Element or DocType node and insert the decl right
74 # before it. If there is no such node, just insert the child at the
75 # end. If there is a child and it is an DocType, then replace it.
76 insert_before_index = 0
78 insert_before_index += 1
79 x.kind_of?(Element) || x.kind_of?(DocType)
81 if @children[ insert_before_index ] # Not null = not end of list
82 if @children[ insert_before_index ].kind_of DocType
83 @children[ insert_before_index ] = child
85 @children[ index_before_index-1, 0 ] = child
87 else # Insert at end of list
88 @children[insert_before_index] = child
93 raise "attempted adding second root element to document" if @elements.size > 1
99 def add_element(arg=nil, arg2=nil)
101 raise "attempted adding second root element to document" if @elements.size > 1
105 # @return the root Element of the document, or nil if this document
110 #@children.find { |item| item.kind_of? Element }
113 # @return the DocType child of the document, if one exists,
116 @children.find { |item| item.kind_of? DocType }
119 # @return the XMLDecl of this document; if no XMLDecl has been
120 # set, the default declaration is returned.
123 return rv if rv.kind_of? XMLDecl
124 rv = @children.unshift(XMLDecl.default)[0]
127 # @return the XMLDecl version of this document as a String.
128 # If no XMLDecl has been set, returns the default version.
133 # @return the XMLDecl encoding of this document as a String.
134 # If no XMLDecl has been set, returns the default encoding.
139 # @return the XMLDecl standalone value of this document as a String.
140 # If no XMLDecl has been set, returns the default setting.
142 xml_decl().stand_alone?
145 # Write the XML tree out, optionally with indent. This writes out the
146 # entire XML document, including XML declarations, doctype declarations,
147 # and processing instructions (if any are given).
148 # A controversial point is whether Document should always write the XML
149 # declaration (<?xml version='1.0'?>) whether or not one is given by the
150 # user (or source document). REXML does not write one if one was not
151 # specified, because it adds unneccessary bandwidth to applications such
156 # output an object which supports '<< string'; this is where the
157 # document will be written.
159 # An integer. If -1, no indenting will be used; otherwise, the
160 # indentation will be this number of spaces, and children will be
161 # indented an additional amount. Defaults to -1
163 # If transitive is true and indent is >= 0, then the output will be
164 # pretty-printed in such a way that the added whitespace does not affect
165 # the absolute *value* of the document -- that is, it leaves the value
166 # and number of Text nodes in the document unchanged.
168 # Internet Explorer is the worst piece of crap to have ever been
169 # written, with the possible exception of Windows itself. Since IE is
170 # unable to parse proper XML, we have to provide a hack to generate XML
171 # that IE's limited abilities can handle. This hack inserts a space
172 # before the /> on empty tags. Defaults to false
173 def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
174 output = Output.new( output, xml_decl.encoding ) if xml_decl.encoding != "UTF-8" && !output.kind_of?(Output)
175 @children.each { |node|
176 indent( output, indent ) if node.node_type == :element
177 if node.write( output, indent, transitive, ie_hack )
178 output << "\n" unless indent<0 or node == @children[-1]
184 def Document::parse_stream( source, listener )
185 Parsers::StreamParser.new( source, listener ).parse
190 Parsers::TreeParser.new( source, self ).parse