Use XQuery to check if namespace prefix of an XML document is redefined throughout the file

Viewed 178

How to check if an XML document maps the same namespace prefix to two different namespace URIs (at different points).

If the condition above is met, print "YES", else do not print anything.

The input to the XQuery can be any well-formed XML file.

I am very new to XQuery and I just know the basics of XPath 1.0 and 2.0

The way I want to tackle the problem is the following: Get list of all namespace definitions in the file and then check if any of those appears twice in the file.

Example of attribute list we want to obtain (xmlns:f, xmlns:l, xmlns:d, xmlns:f). Then if any of the element of the list appears more than one time in the list, we need to return "YES", but I have no idea how to do this.

1 Answers

Assuming support for XQuery 3.1 with maps:

let $bindings := map:merge(
   for $e in //*, $p in in-scope-prefixes($e)
   return map{$p, namespace-uri-for-prefix($p, $e)},
   map{'duplicates':'combine'}
)
return 'YES'[some $k in map:keys($bindings) satisfies count(distinct-values($bindings($k))) gt 1]

Not tested.

The option duplicates:combine is a bit unfortunate here, as it collects all the namespaces bound to the prefix, including duplicates, and then eliminates duplicates later. The next Saxon release has an additional option that allows you to eliminate duplicates as you go.

It's unfortunate that XQuery doesn't support the namespace axis. With an XPath 3.1 processor that supports the namespace axis you can do

let $bindings := //namespace::*, 
    $prefixes := distinct-values($bindings!name())
return 'YES'[some $p in $prefixes 
             satisfies count(distinct-values(
                         $bindings[name()=$p]/string(.)) gt 1)]
Related