From e5fba587764361faabd9d577c82609b33e46a57d Mon Sep 17 00:00:00 2001 From: NAITOH Jun Date: Tue, 8 Sep 2026 21:25:49 +0900 Subject: [PATCH] Stop substituting entities with an empty value `String#gsub("")` matches at every position, so an entity declared with an empty value was inserted between every character when a text node or an attribute value was normalized. That also kept the other entities from matching the text: "abc aaa" -> "abc &a;" # was "∅a∅b∅c∅ ..." Substituting an empty entity is pointless -- a reference to it and its replacement text are equivalent -- so skipping it loses nothing. --- lib/rexml/text.rb | 7 ++++--- test/test_attribute.rb | 12 ++++++++++++ test/test_text.rb | 12 ++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/rexml/text.rb b/lib/rexml/text.rb index ed4bff40..d0ff549a 100644 --- a/lib/rexml/text.rb +++ b/lib/rexml/text.rb @@ -356,9 +356,10 @@ def Text::normalize( input, doctype=nil, entity_filter=nil ) if doctype # Replace all ampersands that aren't part of an entity doctype.entities.each_value do |entity| - copy = copy.gsub( entity.value, - "&#{entity.name};" ) if entity.value and - not( entity_filter and entity_filter.include?(entity.name) ) + # Skip an empty value because String#gsub("") matches at every position + next if entity.value.nil? or entity.value.empty? + next if entity_filter and entity_filter.include?(entity.name) + copy = copy.gsub( entity.value, "&#{entity.name};" ) end else # Replace all ampersands that aren't part of an entity diff --git a/test/test_attribute.rb b/test/test_attribute.rb index dc5c331d..4928b664 100644 --- a/test/test_attribute.rb +++ b/test/test_attribute.rb @@ -17,5 +17,17 @@ def test_namespace_declaration assert_equal(true, REXML::Attribute.new("xmlns:name").namespace_declaration?) # REXML::Attribute.new("xmlns:xmlns") is not tested because it's invalid end + + def test_to_string_entity + document = REXML::Document.new(<<-XML) + + +]> + + XML + document.root.add_attribute("attr", "abc aaa") + assert_equal("", document.root.to_s) + end end end diff --git a/test/test_text.rb b/test/test_text.rb index 6dd2a488..f5df2513 100644 --- a/test/test_text.rb +++ b/test/test_text.rb @@ -51,6 +51,18 @@ def test_new_text_entity_filter_custom Text.new(text, false, document.root, nil, ["b"]).to_s) end + def test_new_text_empty_entity + document = REXML::Document.new(<<-XML) + + +]> + + XML + assert_equal("abc &a;", + Text.new("abc aaa", false, document.root).to_s) + end + def test_shift_operator_chain text = Text.new("original\r\n") text << "append1\r\n" << "append2\r\n"