Hi Jason,

This seems to be a bug in Xerces.

As you've noticed each node's user data is actually stored on the Document
node. When a node is adopted into another document all the user data of its
descendants is left behind in a table in the source document. Couldn't find
anything in the spec which supports that behaviour. I believe all the user
data should get transferred as well. Can you open a bug report here:
http://issues.apache.org/jira/browse/XERCESJ.

Thanks.

Michael Glavassevich
XML Parser Development
IBM Toronto Lab
E-mail: [EMAIL PROTECTED]
E-mail: [EMAIL PROTECTED]

"Jason Baker" <[EMAIL PROTECTED]> wrote on 09/10/2008 09:25:38 PM:

> Hello,
>
> I am working with the java version of xerces and am having trouble
> figuring out how to get adopted nodes to carry attached UserData objects
> along with them from one document object to another.
>
> In particular, I am trying to add Line Number information to Node objects
> in a xerces document. There is a handy xerces sample application that
> shows me how to do this, you can find the sample in
> Xerces-J-src.2.9.1.zip:xerces-2_9_1\samples\dom\DOMAddLines.java.
>
> This sample is great! It got me started in the right direction and works
> perfectly as long as you are not trying to clone nodes or adopt them to
> other documents with the expectation that your line numbers will stick.
>
> The first problem is that the sample does not provide a UserDataHandler
> when it calls setUserData(), so I changed my sample around to include my
> own handler:
>
> public class DOMLineNumberUserDataHandler implements UserDataHandler
> {
>
>   public void handle(short operation, String key, Object data, Node src,
> Node dst)
>   {
>     System.out.println("\nDOMLineNumberUserDataHandler Called:
operation="
> + operation + ", key=" +
>             key + ", data=" + data + ", src=" + src + ", dst=" + dst);
>
>     if (operation == UserDataHandler.NODE_ADOPTED)
>     {
>       System.out.println("(Current Operation is NODE_ADOPTED)");
>     }
>
>     if (dst != null)
>     {
>       dst.setUserData(key, data, this);
>     }
>    }
>
> }
>
> That's my handler code, then the sample needed to be changed around, I
> added a private UserDataHandler like so at the top of the DOMAddLines:
>
> private UserDataHandler userDataHandler = new
DOMLineNumberUserDataHandler();
>
> Then I changed the two lines from this:
>
> node.setUserData("startLine", String.valueOf(locator.getLineNumber()),
null);
>
> to this:
>
> node.setUserData("startLine", String.valueOf(locator.getLineNumber()),
> this.userDataHandler);
>
> Those two lines are in the DOMAddLines "startDocument" and "startElement"
> methods.
>
> With my handler in place, cloning nodes works beautifully.
>
> However, adopting nodes from one document to another does not work.
>
> The scenario we're developing for is this: We have XML a, it has some
> specialized tags that are place holders for other XML documents (b) we
> pull in. When our code is searching through the DOM tree for XML-a and we
> find one of these tags that needs to be replaced with XML-b's contents,
> then we read in XML-b, adopt XML-b's nodes into the XML-a document, and
do
> the replace. The adoptNodes call does not copy UserData for nodes other
> than the top level node we're adopting though. We determined that we must
> call adoptNode on the XML-b's root element before sticking the nodes into
> the XML-a DOM tree in order to avoid 'WRONG_DOCUMENT_ERR' errors.
>
> Here is a brief test case that exemplifies the behaviour I am seeing:
>
> public void testLineNumberStuff()
> {
>   try
>   {
>     String originalDocument =
> "<some>\n<document>\n<with>\n<no>content</no></with></document></some>";
>     DOMParser originalParser = new DOMAddLines();
>     originalParser.parse(new InputSource(new
> StringReader(originalDocument)));
>     Element originalDocumentElement =
> originalParser.getDocument().getDocumentElement();
>
>     String adoptingDocument = "<some>\n<other>\ndocument</other></some>";
>     DOMParser adoptingParser = new DOMAddLines();
>     adoptingParser.parse(new InputSource(new
> StringReader(adoptingDocument)));
>     Element adoptingDocumentElement =
> adoptingParser.getDocument().getDocumentElement();
>
>     DOMAddLines someUnrelatedParserForPrinting = new DOMAddLines();
>
>     System.out.println("ORIGINAL DOCUMENT BEFORE ADOPTION:");
>     someUnrelatedParserForPrinting.print(originalDocumentElement);
>
>     System.out.println("ADOPTING DOCUMENT BEFORE ADOPTION: ");
>     someUnrelatedParserForPrinting.print(adoptingDocumentElement);
>
>     adoptingDocumentElement.getOwnerDocument().
> adoptNode(originalDocumentElement);
>
>     someUnrelatedParserForPrinting = new DOMAddLines();
>
>     System.out.println("ORIGINAL DOCUMENT AFTER ADOPTION:");
>     someUnrelatedParserForPrinting.print(originalDocumentElement);
>
>     System.out.println("ADOPTING DOCUMENT AFTER ADOPTION: ");
>     someUnrelatedParserForPrinting.print(adoptingDocumentElement);
>   }
>   catch (Exception e)
>   {
>     System.out.println("Caught exception: " + e.getMessage());
>     e.printStackTrace();
>   }
> }
>
> The output of this test case is:
>
> ORIGINAL DOCUMENT BEFORE ADOPTION:
>
> content4:<no></no>3:<with></with>2:<document></document>1:<some></some>
>
> ADOPTING DOCUMENT BEFORE ADOPTION:
>
> document2:<other></other>1:<some></some>
>
> DOMLineNumberUserDataHandler Called: operation=5, key=startLine, data=1,
> src=[some: null], dst=null
> (Current Operation is NODE_ADOPTED)
>
> ORIGINAL DOCUMENT AFTER ADOPTION:
>
> contentnull:<no></no>null:<with></with>null:<document></document>1:
> <some></some>
>
> ADOPTING DOCUMENT AFTER ADOPTION:
>
>
> document2:<other></other>1:<some></some>
>
> As you can see, all of the line number UserData objects except one are
> dropped during the adoptNode scenario. All of the numbers in the
"ORIGINAL
> DOCUMENT" are replaced with nulls except for the "1" that is the UserData
> on the top-most node in our example DOM tree.
>
> I have dug around a little in an eclipse debug view of the Document
> objects and I have also dug around a little on google and have not found
a
> clear statement of this issue elsewhere, but I have seen discussion of
the
> UserData objects being stored in the parent Document object in a hash
map.
> It appears only the initial root node's UserData in the DOM tree for a
> document is being "adopted" over when an adoptNode call is made with that
> root node.
>
> Am I doing this incorrectly? Is the correct way to get the UserData
copied
> over simply a manual traversal of the DOM tree I want to adopt and
calling
> adoptNode() one each of those nodes?
>
> Thanks for your time,
>
> Jason Baker
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to