OSDN Git Service

d795d556909e6b867eee192013bb8793d3acf51d
[redminele/redminele.git] / ruby / lib / ruby / gems / 1.8 / gems / activesupport-2.3.12 / lib / active_support / xml_mini / jdom.rb
1 raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFORM =~ /java/
2
3 require 'jruby'
4 include Java
5
6 import javax.xml.parsers.DocumentBuilder unless defined? DocumentBuilder
7 import javax.xml.parsers.DocumentBuilderFactory unless defined? DocumentBuilderFactory
8 import java.io.StringReader unless defined? StringReader
9 import org.xml.sax.InputSource unless defined? InputSource
10 import org.xml.sax.Attributes unless defined? Attributes
11 import org.w3c.dom.Node unless defined? Node
12
13 # = XmlMini JRuby JDOM implementation
14 module ActiveSupport
15   module XmlMini_JDOM #:nodoc:
16     extend self
17
18     CONTENT_KEY = '__content__'.freeze
19
20     NODE_TYPE_NAMES = %w{ATTRIBUTE_NODE CDATA_SECTION_NODE COMMENT_NODE DOCUMENT_FRAGMENT_NODE
21     DOCUMENT_NODE DOCUMENT_TYPE_NODE ELEMENT_NODE ENTITY_NODE ENTITY_REFERENCE_NODE NOTATION_NODE
22     PROCESSING_INSTRUCTION_NODE TEXT_NODE}
23
24     node_type_map = {}
25     NODE_TYPE_NAMES.each { |type| node_type_map[Node.send(type)] = type }
26
27     # Parse an XML Document string into a simple hash using Java's jdom.
28     # string::
29     #   XML Document string to parse
30     def parse(string)
31       if string.blank?
32         {}
33       else
34         @dbf = DocumentBuilderFactory.new_instance
35         xml_string_reader = StringReader.new(string)
36         xml_input_source = InputSource.new(xml_string_reader)
37         doc = @dbf.new_document_builder.parse(xml_input_source)
38         merge_element!({}, doc.document_element)
39       end
40     end
41
42     private
43
44     # Convert an XML element and merge into the hash
45     #
46     # hash::
47     #   Hash to merge the converted element into.
48     # element::
49     #   XML element to merge into hash
50     def merge_element!(hash, element)
51       merge!(hash, element.tag_name, collapse(element))
52     end
53
54     # Actually converts an XML document element into a data structure.
55     #
56     # element::
57     #   The document element to be collapsed.
58     def collapse(element)
59       hash = get_attributes(element)
60
61       child_nodes = element.child_nodes
62       if child_nodes.length > 0
63         for i in 0...child_nodes.length
64           child = child_nodes.item(i)
65           merge_element!(hash, child) unless child.node_type == Node.TEXT_NODE
66         end
67         merge_texts!(hash, element) unless empty_content?(element)
68         hash
69       else
70         merge_texts!(hash, element)
71       end
72     end
73
74     # Merge all the texts of an element into the hash
75     #
76     # hash::
77     #   Hash to add the converted emement to.
78     # element::
79     #   XML element whose texts are to me merged into the hash
80     def merge_texts!(hash, element)
81       text_children = texts(element)
82       if text_children.join.empty?
83         hash
84       else
85         # must use value to prevent double-escaping
86         merge!(hash, CONTENT_KEY, text_children.join)
87       end
88     end
89
90     # Adds a new key/value pair to an existing Hash. If the key to be added
91     # already exists and the existing value associated with key is not
92     # an Array, it will be wrapped in an Array. Then the new value is
93     # appended to that Array.
94     #
95     # hash::
96     #   Hash to add key/value pair to.
97     # key::
98     #   Key to be added.
99     # value::
100     #   Value to be associated with key.
101     def merge!(hash, key, value)
102       if hash.has_key?(key)
103         if hash[key].instance_of?(Array)
104           hash[key] << value
105         else
106           hash[key] = [hash[key], value]
107         end
108       elsif value.instance_of?(Array)
109         hash[key] = [value]
110       else
111         hash[key] = value
112       end
113       hash
114     end
115
116     # Converts the attributes array of an XML element into a hash.
117     # Returns an empty Hash if node has no attributes.
118     #
119     # element::
120     #   XML element to extract attributes from.
121     def get_attributes(element)
122       attribute_hash = {}
123       attributes = element.attributes
124       for i in 0...attributes.length
125          attribute_hash[attributes.item(i).name] =  attributes.item(i).value
126        end
127       attribute_hash
128     end
129
130     # Determines if a document element has text content
131     #
132     # element::
133     #   XML element to be checked.
134     def texts(element)
135       texts = []
136       child_nodes = element.child_nodes
137       for i in 0...child_nodes.length
138         item = child_nodes.item(i)
139         if item.node_type == Node.TEXT_NODE
140           texts << item.get_data
141         end
142       end
143       texts
144     end
145
146     # Determines if a document element has text content
147     #
148     # element::
149     #   XML element to be checked.
150     def empty_content?(element)
151       text = ''
152       child_nodes = element.child_nodes
153       for i in 0...child_nodes.length
154         item = child_nodes.item(i)
155         if item.node_type == Node.TEXT_NODE
156           text << item.get_data.strip
157         end
158       end
159       text.strip.length == 0
160     end
161   end
162 end