According to the XML namespace specifications, the default namespace does not apply directly to the attributes, it applies to unprefixed elements, and elements determine the behavior of unprefixed attributes. So, I would expect that output_tree/output_doc_tree would raise if we try to print an attribute whose namespace is:
- the default namespace.
- is not bound to any prefix.
However, output_tree/output_doc_tree happily chop away the namespace if it's equal to the default namespace. Additionally, they generate the same output for the attributes whether the attribute is the default namespace or whether the attribute is unprefixed, which is also incorrect (I think) because they have different meanings.
Here's a test that reproduces the issue and demonstrates the various cases:
module Simple = struct
open! Xmlm
type attribute =
| Default_namespace of string
| Namespace_prefix of
{ prefix : string
; namespace : string
}
| Generic of { namespace : string }
type t =
{ namespace : string
; attributes : attribute list
; children : t list
}
let to_string t =
let buffer = Buffer.create 16 in
let output = make_output ~indent:(Some 2) (`Buffer buffer) in
output_doc_tree
(fun { namespace; attributes; children } ->
let attributes =
List.map
(function
| Default_namespace namespace -> (ns_xmlns, "xmlns"), namespace
| Namespace_prefix { prefix; namespace } -> (ns_xmlns, prefix), namespace
| Generic { namespace } -> (namespace, "generic"), namespace)
attributes
in
`El (((namespace, "element"), attributes), children))
output
(None, t);
Buffer.contents buffer
;;
end
let%expect_test "Xmlm" =
let open! Xmlm in
let default_ns = "default-ns" in
let element_ns = "element-ns" in
let print ~attribute_namespace =
Simple.to_string
{ namespace = ""
; attributes =
[ Default_namespace default_ns
; Namespace_prefix { prefix = "element"; namespace = element_ns }
]
; children =
[ { namespace = element_ns
; attributes = [ Generic { namespace = attribute_namespace } ]
; children = []
}
]
}
|> print_endline
in
(* When the attribute's namespace is the default namespace. *)
print ~attribute_namespace:default_ns;
[%expect
{|
<?xml version="1.0" encoding="UTF-8"?>
<element xmlns="default-ns" xmlns:element="element-ns">
<element:element generic="default-ns"/>
</element> |}];
(* When the attribute's namespace is not specified. *)
print ~attribute_namespace:"";
[%expect
{|
<?xml version="1.0" encoding="UTF-8"?>
<element xmlns="default-ns" xmlns:element="element-ns">
<element:element generic=""/>
</element> |}];
(* When the attribute's namespace is a bound namespace. *)
print ~attribute_namespace:element_ns;
[%expect
{|
<?xml version="1.0" encoding="UTF-8"?>
<element xmlns="default-ns" xmlns:element="element-ns">
<element:element element:generic="element-ns"/>
</element> |}]
;;
According to the XML namespace specifications, the default namespace does not apply directly to the attributes, it applies to unprefixed elements, and elements determine the behavior of unprefixed attributes. So, I would expect that
output_tree/output_doc_treewould raise if we try to print an attribute whose namespace is:However,
output_tree/output_doc_treehappily chop away the namespace if it's equal to the default namespace. Additionally, they generate the same output for the attributes whether the attribute is the default namespace or whether the attribute is unprefixed, which is also incorrect (I think) because they have different meanings.Here's a test that reproduces the issue and demonstrates the various cases: