[xml] xmlRemoveRef/xmlAddRef + validation weirdness


I recently ran across some inconsistency while using RelaxNG
validation along with document tree manipulation.

main goal:
        re-validating a document after removals and insertions of
        nodes using the tree API.

basically, I'm doing like this:

        - xmlUnlinkNode or xmlAddChild/AddNextSibling/...
        - xmlRelaxNGValidateDoc

the first issue I encountered is that xmlRelaxNGValidateDoc doesn't seem
to perform a real validation pass when doc->psvi != NULL (which is set
during the first xmlRelaxNGValidateDoc call).
I worked around this by resetting it to NULL.
might be a wrong thing to do, but I haven't found anything cleaner. any
opinions about that ?

the second problem is that IDREFs aren't removed at all during an
xmlUnlinkNode call, whatever the schema type is used (but this is done
for IDs at tree.c:8771).

since I need strict IDREF checking based on my schema after modifying
the document structure, I decided to call xmlRemoveRef "manually" (second
wrong-doing ?) to remove known IDREF attributes whenever I remove nodes
containing them from the document tree.

everything works fine like this, until I try to add a new node,
containing a previously removed IDREF.
insertion using xmlAddChild/AddNextSibling/... doesn't trigger any error,
then making a call to xmlRelaxNGValidateDoc on the modified
document (using the doc->psvi = NULL hack), returns 0 (seemingly no error),
but generates the following error:

        validity error : xmlAddRef: Reference list insertion failed!

which is tracked down to valid.c:2993.

what it boils down to is that xmlRemoveRef, when removing the last IDREF
to a specific ID, updates the corresponding entry in the doc's IDREFs
hash table using a NULL value, instead of removing the entry
altogether (valid.c:3111).

xmlAddRef (called by xmlRelaxNGValidateDoc) then looks up the ID value
in the same table (valid.c:2986), gets a hit with the NULL value updated
by xmlRemoveRef, creates a new ref_list, then tries to add it using
xmlHashAddEntry, but this fails because the entry is already present
(just containing a NULL value).

I've made a simple patch for this, which simply consists of replacing
xmlRemoveRef's xmlHashUpdateEntry call with an xmlHashRemoveEntry, and
it apparently solves the problem.
regression tests still work with this modification.

I'm just not sure whether this is really pertinent when looking at the hacks
I had to do to get there...

I attach a tarball consisting of:

        - test-removeref.c: sample code demonstrating the issue (as well
          as my questionable hacks), using XSD and RelaxNG validation

        - test-removeref.xml: sample XML file to be used with the demo

        - test-removeref.rnc: RelaxNG Compact source for the schema
          (to be processed using Trang)

        - xmlRemoveRef.patch: simple patch to solve the problem

        - a Makefile to be launched using "make test"

the unzipped tarball is there just in case (including the compiled
RelaxNG and XSD schemas):

(the tarball is here as well: http://www.chx-labs.org/test-removeref.tar.gz)

all this was done against libxml version 2.6.22


Gabriel Forté <gab chx-labs org>

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]