1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

[ruby/rexml] Fix attribute's default namespace behavior

NOTE: It's a backward incompatible change. If we have any serious
problems with this change, we may revert this change.

The XML namespace specification says the default namespace doesn't
apply to attribute names but it does in REXML without this change:

https://www.w3.org/TR/xml-names/#uniqAttrs

> the default namespace does not apply to attribute names

REXML reports a parse error for the following XML that is described as
a valid XML in the XML nsmaspace specification without this change:

    <!-- http://www.w3.org is bound to n1 and is the default -->
    <x xmlns:n1="http://www.w3.org"
       xmlns="http://www.w3.org" >
      <good a="1"     b="2" />
      <good a="1"     n1:a="2" />
    </x>

If attribute doesn't have prefix, the attribute should return "" for
both #prefix and #namespace.

https://github.com/ruby/rexml/commit/9e4fd552bc
This commit is contained in:
Kouhei Sutou 2019-01-01 06:32:18 +09:00 committed by Hiroshi SHIBATA
parent 9b36f0a787
commit 0f18bc7fca
4 changed files with 63 additions and 22 deletions

View file

@ -67,15 +67,11 @@ module REXML
# 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"
# e.attributes.get_attribute( "b" ).prefix # -> ""
# a = Attribute.new( "x", "y" )
# a.prefix # -> ""
def prefix
pf = super
if pf == ""
pf = @element.prefix if @element
end
pf
super
end
# Returns the namespace URL, if defined, or nil otherwise
@ -87,9 +83,8 @@ module REXML
# e.attribute("ns:a").namespace # => "http://url"
# e.attribute("nsx:a").namespace # => nil
#
# TODO: This method should always return nil for no namespace
# attribute. Because the default namespace doesn't apply to
# attribute name.
# This method always returns "" for no namespace attribute. Because
# the default namespace doesn't apply to attribute names.
#
# From https://www.w3.org/TR/xml-names/#uniqAttrs
#
@ -99,10 +94,14 @@ module REXML
# e.add_namespace("", "http://example.com/")
# e.namespace # => "http://example.com/"
# e.add_attribute("a", "b")
# e.attribute("a").namespace # => nil
# e.attribute("a").namespace # => ""
def namespace arg=nil
arg = prefix if arg.nil?
@element.namespace arg
if arg == ""
""
else
@element.namespace(arg)
end
end
# Returns true if other is an Attribute and has the same name and value,

View file

@ -1133,8 +1133,8 @@ module REXML
elsif old_attr.prefix != value.prefix
# Check for conflicting namespaces
if value.prefix != "xmlns" and old_attr.prefix != "xmlns"
old_namespace = @element.namespace(old_attr.prefix)
new_namespace = @element.namespace(value.prefix)
old_namespace = old_attr.namespace
new_namespace = value.namespace
if old_namespace == new_namespace
raise ParseException.new(
"Namespace conflict in adding attribute \"#{value.name}\": "+

View file

@ -493,17 +493,11 @@ module REXML
if prefix.nil?
raw_node.name == name
elsif prefix.empty?
# FIXME: This DOUBLES the time XPath searches take
raw_node.name == name and
raw_node.namespace == raw_node.element.namespace
raw_node.name == name and raw_node.namespace == ""
else
# FIXME: This DOUBLES the time XPath searches take
ns = get_namespace(raw_node.element, prefix)
if ns.empty?
raw_node.name == name and raw_node.prefix.empty?
else
raw_node.name == name and raw_node.namespace == ns
end
raw_node.name == name and raw_node.namespace == ns
end
else
false

View file

@ -1,4 +1,4 @@
# coding: binary
# -*- coding: utf-8 -*-
# frozen_string_literal: false
require_relative "rexml_test_utils"
@ -116,6 +116,54 @@ module REXMLTests
name4='test4'/>).join(' '), e.to_s
end
def test_attribute_namespace_conflict
# https://www.w3.org/TR/xml-names/#uniqAttrs
message = <<-MESSAGE
Duplicate attribute "a"
Line: 4
Position: 140
Last 80 unconsumed characters:
MESSAGE
assert_raise_with_message(REXML::ParseException, message) do
Document.new(<<-XML)
<!-- http://www.w3.org is bound to n1 and n2 -->
<x xmlns:n1="http://www.w3.org"
xmlns:n2="http://www.w3.org" >
<bad a="1" a="2" />
<bad n1:a="1" n2:a="2" />
</x>
XML
end
end
def test_attribute_default_namespace
# https://www.w3.org/TR/xml-names/#uniqAttrs
document = Document.new(<<-XML)
<!-- http://www.w3.org is bound to n1 and is the default -->
<x xmlns:n1="http://www.w3.org"
xmlns="http://www.w3.org" >
<good a="1" b="2" />
<good a="1" n1:a="2" />
</x>
XML
attributes = document.root.elements.collect do |element|
element.attributes.each_attribute.collect do |attribute|
[attribute.prefix, attribute.namespace, attribute.name]
end
end
assert_equal([
[
["", "", "a"],
["", "", "b"],
],
[
["", "", "a"],
["n1", "http://www.w3.org", "a"],
],
],
attributes)
end
def test_cdata
test = "The quick brown fox jumped
& < & < \" '