Make XmlDeclaration a ProcessingInstruction

This allows Oga to parse documents that contain an XML declaration at a
place other than at the document root. Oga still only assigns the XML
declaration to the document whenever it is at the top-level. This
matches libxml/XML specification behaviour as far as I can tell.
This commit is contained in:
Yorick Peterse 2016-09-17 14:39:07 +02:00
parent d40baf0c72
commit 116b9b0ceb
No known key found for this signature in database
GPG Key ID: EDD30D2BEB691AC9
6 changed files with 65 additions and 20 deletions

View File

@ -35,8 +35,8 @@ require 'oga/xml/character_node'
require 'oga/xml/text'
require 'oga/xml/comment'
require 'oga/xml/cdata'
require 'oga/xml/xml_declaration'
require 'oga/xml/processing_instruction'
require 'oga/xml/xml_declaration'
require 'oga/xml/doctype'
require 'oga/xml/namespace'
require 'oga/xml/default_namespace'

View File

@ -48,12 +48,14 @@ module Oga
callback = :on_comment
when Oga::XML::Attribute
callback = :on_attribute
when Oga::XML::XmlDeclaration
# This must come before ProcessingInstruction since XmlDeclaration
# extends ProcessingInstruction.
callback = :on_xml_declaration
when Oga::XML::ProcessingInstruction
callback = :on_processing_instruction
when Oga::XML::Doctype
callback = :on_doctype
when Oga::XML::XmlDeclaration
callback = :on_xml_declaration
when Oga::XML::Document
callback = :on_document
children = true

View File

@ -1,9 +1,7 @@
module Oga
module XML
# Class containing information about an XML declaration tag.
class XmlDeclaration
include ToXML
class XmlDeclaration < ProcessingInstruction
# @return [String]
attr_accessor :version
@ -20,9 +18,12 @@ module Oga
# @option options [String] :encoding
# @option options [String] :standalone
def initialize(options = {})
super
@version = options[:version] || '1.0'
@encoding = options[:encoding] || 'UTF-8'
@standalone = options[:standalone]
@name = 'xml'
end
# @return [String]

View File

@ -36,4 +36,28 @@ describe Oga::XML::Parser do
@node.encoding.should == 'foo'
end
end
it 'parses an XML declaration inside an element' do
document = parse('<foo><?xml ?></foo>')
document.children[0].should be_an_instance_of(Oga::XML::Element)
document.children[0].children[0].should be_an_instance_of(Oga::XML::XmlDeclaration)
end
it 'parses an XML declaration preceded by an element' do
document = parse('<foo /><?xml ?>')
document.xml_declaration.should be_an_instance_of(Oga::XML::XmlDeclaration)
document.children[0].should be_an_instance_of(Oga::XML::Element)
end
it 'parses an XML declaration preceded by an element with a common ancestor' do
document = parse('<root><a /><?xml ?></root>')
root = document.children[0]
root.children[0].should be_an_instance_of(Oga::XML::Element)
root.children[1].should be_an_instance_of(Oga::XML::XmlDeclaration)
root.children[1].previous.should == root.children[0]
end
end

View File

@ -28,6 +28,12 @@ describe Oga::XML::XmlDeclaration do
end
end
describe '#name' do
it 'returns the name of the node' do
described_class.new.name.should == 'xml'
end
end
describe '#to_xml' do
before do
@instance = described_class.new(

View File

@ -1,24 +1,36 @@
require 'spec_helper'
describe Oga::XPath::Compiler do
before do
@document = parse('<a><?a foo ?><b><?b bar ?></b></a>')
describe 'using a regular processing instruction' do
before do
@document = parse('<a><?a foo ?><b><?b bar ?></b></a>')
@proc_ins1 = @document.children[0].children[0]
@proc_ins2 = @document.children[0].children[1].children[0]
end
describe 'relative to a document' do
describe 'a/processing-instruction()' do
it 'returns a NodeSet' do
evaluate_xpath(@document).should == node_set(@proc_ins1)
end
@proc_ins1 = @document.children[0].children[0]
@proc_ins2 = @document.children[0].children[1].children[0]
end
describe 'a/b/processing-instruction()' do
it 'returns a NodeSet' do
evaluate_xpath(@document).should == node_set(@proc_ins2)
describe 'relative to a document' do
describe 'a/processing-instruction()' do
it 'returns a NodeSet' do
evaluate_xpath(@document).should == node_set(@proc_ins1)
end
end
describe 'a/b/processing-instruction()' do
it 'returns a NodeSet' do
evaluate_xpath(@document).should == node_set(@proc_ins2)
end
end
end
end
describe 'using an XML declaration' do
it 'returns a NodeSet containing the XmlDeclaration' do
document = parse('<root><?xml version="1.0" ?></root>')
xml_decl = document.children[0].children[0]
evaluate_xpath(document, 'root/processing-instruction()')
.should == node_set(xml_decl)
end
end
end