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]