LibWeb+LibXML: Preserve element attribute order in XML documents

We now use OrderedHashMap instead of HashMap to ensure that attributes
on XML elements retain their original order.
This commit is contained in:
Andreas Kling 2025-08-21 12:11:41 +02:00 committed by Andreas Kling
commit b7595013c1
Notes: github-actions[bot] 2025-08-22 09:37:04 +00:00
7 changed files with 22 additions and 6 deletions

View file

@ -92,7 +92,7 @@ void XMLDocumentBuilder::set_doctype(XML::Doctype doctype)
m_document->insert_before(document_type, m_document->first_child(), false);
}
void XMLDocumentBuilder::element_start(const XML::Name& name, HashMap<XML::Name, ByteString> const& attributes)
void XMLDocumentBuilder::element_start(const XML::Name& name, OrderedHashMap<XML::Name, ByteString> const& attributes)
{
if (m_has_error)
return;

View file

@ -32,7 +32,7 @@ public:
private:
virtual void set_source(ByteString) override;
virtual void set_doctype(XML::Doctype) override;
virtual void element_start(XML::Name const& name, HashMap<XML::Name, ByteString> const& attributes) override;
virtual void element_start(XML::Name const& name, OrderedHashMap<XML::Name, ByteString> const& attributes) override;
virtual void element_end(XML::Name const& name) override;
virtual void text(StringView data) override;
virtual void comment(StringView data) override;

View file

@ -29,7 +29,7 @@ struct Node {
};
struct Element {
Name name;
HashMap<Name, ByteString> attributes;
OrderedHashMap<Name, ByteString> attributes;
Vector<NonnullOwnPtr<Node>> children;
};

View file

@ -700,7 +700,7 @@ ErrorOr<NonnullOwnPtr<Node>, ParseError> Parser::parse_empty_element_tag()
TRY(expect("<"sv));
auto name = TRY(parse_name());
HashMap<Name, ByteString> attributes;
OrderedHashMap<Name, ByteString> attributes;
while (true) {
if (auto result = skip_whitespace(Required::Yes); result.is_error())
@ -854,7 +854,7 @@ ErrorOr<NonnullOwnPtr<Node>, ParseError> Parser::parse_start_tag()
auto accept = accept_rule();
auto name = TRY(parse_name());
HashMap<Name, ByteString> attributes;
OrderedHashMap<Name, ByteString> attributes;
while (true) {
if (auto result = skip_whitespace(Required::Yes); result.is_error())

View file

@ -37,7 +37,7 @@ struct Listener {
virtual void set_doctype(XML::Doctype) { }
virtual void document_start() { }
virtual void document_end() { }
virtual void element_start(Name const&, HashMap<Name, ByteString> const&) { }
virtual void element_start(Name const&, OrderedHashMap<Name, ByteString> const&) { }
virtual void element_end(Name const&) { }
virtual void text(StringView) { }
virtual void cdata_section(StringView) { }

View file

@ -0,0 +1,5 @@
a
b
c
d
e

View file

@ -0,0 +1,11 @@
<!doctype html>
<script src="../include.js"></script>
<script>
test(() => {
const doc = new DOMParser().parseFromString(`<xml><foo a='1' b='2' c='3' d='4' e='5'/></xml>`, "application/xml");
const e = doc.firstChild.firstChild;
for (const a of e.attributes) {
println(a.name);
}
});
</script>