From bdb76cefc528f3e8a94ea103e93ff83aaaf4f71f Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 2 Apr 2014 22:30:45 +0200 Subject: [PATCH] Dedicated handling of XML declaration nodes. --- lib/oga.rb | 1 + lib/oga/xml/document.rb | 10 +++++-- lib/oga/xml/tree_builder.rb | 23 +++++++++++++- lib/oga/xml/xml_declaration.rb | 38 +++++++++++++++++++++++ spec/oga/xml/document_spec.rb | 17 +++++++++++ spec/oga/xml/tree_builder_spec.rb | 27 +++++++++++++++++ spec/oga/xml/xml_declaration_spec.rb | 45 ++++++++++++++++++++++++++++ 7 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 lib/oga/xml/xml_declaration.rb create mode 100644 spec/oga/xml/xml_declaration_spec.rb diff --git a/lib/oga.rb b/lib/oga.rb index 08fa446..03d0d34 100644 --- a/lib/oga.rb +++ b/lib/oga.rb @@ -10,6 +10,7 @@ require_relative 'oga/xml/document' require_relative 'oga/xml/text' require_relative 'oga/xml/comment' require_relative 'oga/xml/cdata' +require_relative 'oga/xml/xml_declaration' require_relative 'oga/xml/tree_builder' require_relative 'oga/html/parser' diff --git a/lib/oga/xml/document.rb b/lib/oga/xml/document.rb index e587831..db1f373 100644 --- a/lib/oga/xml/document.rb +++ b/lib/oga/xml/document.rb @@ -4,10 +4,16 @@ module Oga # Class description # class Document < Node - attr_accessor :dtd, :xml_version, :encoding + attr_accessor :xml_declaration def to_xml - return children.map(&:to_xml).join('') + xml = children.map(&:to_xml).join('') + + if xml_declaration + xml = xml_declaration.to_xml + xml + end + + return xml end end # Document end # XML diff --git a/lib/oga/xml/tree_builder.rb b/lib/oga/xml/tree_builder.rb index 32dfad7..92877d3 100644 --- a/lib/oga/xml/tree_builder.rb +++ b/lib/oga/xml/tree_builder.rb @@ -18,7 +18,14 @@ module Oga # def on_document(node) document = Document.new - document.children = process_all(node) + + process_all(node).each do |child| + if child.is_a?(XmlDeclaration) + document.xml_declaration = child + else + document.children << child + end + end document.children.each do |child| child.parent = document @@ -27,6 +34,16 @@ module Oga return document end + ## + # @param [Oga::AST::Node] node + # @return [Oga::XML::XmlDeclaration] + # + def on_xml_decl(node) + attributes = process(node.children[0]) + + return XmlDeclaration.new(attributes) + end + ## # @param [Oga::AST::Node] node # @return [Oga::XML::Comment] @@ -103,6 +120,10 @@ module Oga return *node end + def handler_missing(node) + raise "No handler for node type #{node.type.inspect}" + end + private ## diff --git a/lib/oga/xml/xml_declaration.rb b/lib/oga/xml/xml_declaration.rb new file mode 100644 index 0000000..8642a88 --- /dev/null +++ b/lib/oga/xml/xml_declaration.rb @@ -0,0 +1,38 @@ +module Oga + module XML + ## + # + # + class XmlDeclaration + attr_accessor :version, :encoding, :standalone + + ## + # @param [Hash] options + # + # @option options [String] :version The XML version. + # @option options [String] :encoding The XML encoding. + # @option options [String] :standalone + # + def initialize(options = {}) + options.each do |key, value| + instance_variable_set("@#{key}", value) if respond_to?(key) + end + + @version ||= '1.0' + @encoding ||= 'UTF-8' + end + + def to_xml + pairs = [] + + [:version, :encoding, :standalone].each do |getter| + value = send(getter) + + pairs << %Q{#{getter}="#{value}"} if value + end + + return "" + end + end # XmlDeclaration + end # XML +end # Oga diff --git a/spec/oga/xml/document_spec.rb b/spec/oga/xml/document_spec.rb index 7a5632f..61220e4 100644 --- a/spec/oga/xml/document_spec.rb +++ b/spec/oga/xml/document_spec.rb @@ -29,4 +29,21 @@ describe Oga::XML::Document do @document.to_xml.should == '' end end + + context '#to_xml with XML declarations' do + before do + decl = Oga::XML::XmlDeclaration.new(:version => '5.0') + children = [Oga::XML::Comment.new(:text => 'foo')] + + @document = described_class.new( + :xml_declaration => decl, + :children => children + ) + end + + example 'include the XML of the declaration tag' do + @document.to_xml + .should == '' + end + end end diff --git a/spec/oga/xml/tree_builder_spec.rb b/spec/oga/xml/tree_builder_spec.rb index 83dbc08..11b5c05 100644 --- a/spec/oga/xml/tree_builder_spec.rb +++ b/spec/oga/xml/tree_builder_spec.rb @@ -20,6 +20,33 @@ describe Oga::XML::TreeBuilder do end end + context '#on_document with XML declarations' do + before do + decl = s(:xml_decl, s(:attributes, s(:attribute, 'encoding', 'UTF-8'))) + node = s(:document, decl) + @tag = @builder.process(node) + end + + example 'set the XML declaration of the document' do + @tag.xml_declaration.is_a?(Oga::XML::XmlDeclaration).should == true + end + end + + context '#on_xml_decl' do + before do + node = s(:xml_decl, s(:attributes, s(:attribute, 'encoding', 'UTF-8'))) + @tag = @builder.process(node) + end + + example 'return an XmlDeclaration node' do + @tag.is_a?(Oga::XML::XmlDeclaration).should == true + end + + example 'include the encoding of the tag' do + @tag.encoding.should == 'UTF-8' + end + end + context '#on_element' do context 'simple elements' do before do diff --git a/spec/oga/xml/xml_declaration_spec.rb b/spec/oga/xml/xml_declaration_spec.rb new file mode 100644 index 0000000..6e2f7a7 --- /dev/null +++ b/spec/oga/xml/xml_declaration_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' + +describe Oga::XML::XmlDeclaration do + context 'setting attributes' do + example 'set the version via the constructor' do + described_class.new(:version => '1.0').version.should == '1.0' + end + + example 'set the version via a setter' do + instance = described_class.new + instance.version = '1.0' + + instance.version.should == '1.0' + end + end + + context 'default attribute values' do + before do + @instance = described_class.new + end + + example 'set the default version' do + @instance.version.should == '1.0' + end + + example 'set the default encoding' do + @instance.encoding.should == 'UTF-8' + end + end + + context '#to_xml' do + before do + @instance = described_class.new( + :version => '1.0', + :encoding => 'UTF-8', + :standalone => 'yes' + ) + end + + example 'generate the corresponding XML' do + @instance.to_xml + .should == '' + end + end +end