dnault / xml-patch

Java implementation of RFC 5261: An XML Patch Operations Framework Utilizing XPath Selectors
Apache License 2.0
26 stars 6 forks source link

failed to select node in namespaced target document when using default namespace #9

Open henning-meinhardt opened 5 years ago

henning-meinhardt commented 5 years ago

Hi,

I have the following XML target file which declares a default namespace along with other namespaces on its root node:

<configuration
    xmlns="urn:configuration"
    xmlns:acl="urn:acl"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:configuration configuration.xsd">
    ...

I want to add an attribute the the root tag like so:

<diff xmlns="urn:configuration" xmlns:acl="urn:acl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <add sel="configuration" type="@newAttribute">something</add>
</diff>

Applying that patch fails saying

Caused by: java.lang.RuntimeException: com.github.dnault.xmlpatch.PatchException: no matches for selector "configuration"

Switching over to the following patch file resolves the issue:

<diff xmlns:cfg="urn:configuration" xmlns:acl="urn:acl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <add sel="cfg:configuration" type="@newAttribute">something</add>
</diff>

note that <add>ing new nodes works just find using the default namespace declaration, only selecting does not. So in effect I haver to declare the defaultnamespace twice in order to allow selection and addition of new nodes without having to prefix the added nodes one by one with "cfg:" prefix. See the following example:

<diff xmlns="urn:configuration" xmlns:cfg="urn:configuration" xmlns:acl="urn:acl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <add sel="cfg:configuration">
        <newElement id="something">
            <param name="someName">someValue</param>
            ...
        </newElement>
    </add>
</diff>

Without the default namespace I would have to prefix every child node of <add>. Without redundant namespace (prefix "cfg") no selection is possible.

Do you have any solution for that?

Kind regards Hennig

dnault commented 5 years ago

Hi Hennig, thanks for reporting this.

Looks like the patcher is not compliant with RFC 5261 section 4.2.1 which says:

When the diff document has a default namespace declaration, any element selector without a prefix MUST be evaluated using that namespace.

For example, the patch operation element of a diff document has an in-scope namespace declaration "xmlns='foo:'" with a selector "sel='bar'". The agent processing this patch MUST then look for a 'bar' element qualified with the 'foo:' namespace, regardless of whether the 'foo:' namespace has a prefix assigned in the target document or what that prefix is.

It's been a while since I worked on the patcher, but let me see if I can get back into it.

dnault commented 5 years ago

After diving into the code, it looks like the fix would involve either parsing and rewriting the selector XPath expression to qualify all unqualified element references, or somehow tricking Jaxen into thinking the references are qualified by the default namespace (maybe by digging into the compiled expression's DefaultNameSteps and setting "hasPrefix" to true... but only for name steps that refer to elements).

I'm unlikely to be able to implement either of those solutions in the foreseeable future.

I think you already found the best workaround: declare a namespace prefix with the same URI as the default namespace, and use that prefix in selector expressions.

henning-meinhardt commented 5 years ago

Hi David, thanks for your quick reply. A can really live with that workaround! Good to know that I can stop thinking of what I might have missed from the RFC. Kind regards Henning