[jdom-interest] JDOM JSR

Amy Lewis amyzing at talsever.com
Fri May 18 16:48:21 PDT 2001

On Fri, May 18, 2001 at 11:31:15AM -0400, Alex Rosen wrote:
>> The particular implementations that drive this need have typically
>> needed to modify both structure and content of the document being
>> processed, in multiple ways.  The mechanism is often methods with a
>> relatively simple signature (using DOM): Document doSomething(Document, Node)
>Can you provide some examples of this? I've never been able to think of a
>real-world case where you'd want to treat all XML objects (elements,
>attributes, text, PIs, etc) the same. That's not to say that there aren't any!
>But it's just harder to be empathetic about a case that you can't really
>imagine happening. It'd be really helpful to see some real-world examples of
>where you'd have a method that wants to be able to receive all these objects
>and treat them at least mostly equally.

I can't do it with JDOM at all, and there are some disclosure issues
using the real code to illustrate DOM examples.  In general, I also try
to avoid mentioning my company or its products directly (talsever isn't
a company, it's an alternate reality), because I'm perfectly aware that
my manner is, on occasion, abrasive and insufficiently well-expressed;
I don't care to have to point out that the folks who pay me to write
code *aren't* also responsible when I write messages to mailing lists.

So, let me see if I can clarify nonetheless, with some serial numbers
filed off and the names changed to protect the guilty.

Let me point out, first of all, that "want[ing] to treat all XML
objects ... the same" isn't quite accurate, and isn't, in my mind, the
purpose of an interface.  The interface (for collections, for instance)
specifies that *some* behavior is shared.  Maybe it's only getParent. 
Which of the following is, do you think, easier to maintain?

if (obj instanceof Node)
    Element parent = ((Node)obj).getParent();
    // do something with element; a lot of code manipulates elements

Element parent = null;
if (obj instanceof Element)
    parent = ((Element)obj).getParent();
if (obj instanceof ProcessingInstruction)
    parent = ((PI)obj).getParent();
if (obj instanceof Attribute)
    parent = ((Attribute)obj).getParent();
if (obj instanceof Text)
    parent = ((Text)obj).getParent();
if (obj instanceof Comment)
    parent = ((Comment)obj).getParent();
// do something with element

As Jason noted elsewhere, you're not likely to do this with
getMixedContent().  The case typically happens when you've passed in a
Node of some sort to a method that needs to check its context.  This
happens a lot when you're using a technology like Schema Adjuncts
(well, it happens a lot if your algorithm is adjunct-driven, meaning
that it finds its own matches in the document based on a limited set in
the adjunct, versus instance-driven, where you walk the entire tree and
wait for a match to trigger an action ... although context is often
important in the latter case as well).

Say, instead, that the results of running an XPath may leave you with
the need to walk over a set of things, and see what they are, and take
action based on that.  The "see what they are" may be equally XPath-y
(if this node has a niece text node, child of the parent's sibling
named "xyzzy", and the content of that node is not "plugh", then, if
this is the "action" attribute of its parent, set the value to "nothing

I'll add here that sooner or later, you're likely to cast to a
subinterface or concrete implementation.  But the field will have
narrowed by then (and I'll also admit that my example above is a bit
contrived: the nodes that get handled a lot are Element, Attribute, and
Text ... but one cast is better than three, and it's often needful to
go from wherever-you-are to the nearest crossroads (and while things
like Entity and CDATA are rare, they occur; it's best to handle those
cases at least, even if you can get away with not handling PIs or

Our system stored information into a database.  The submitted
information was XML (largely), which was in turn wrapped in XML (we had
a lot of need to be able to put things into other documents, and take
them back out) (note that the included XML was BASE-64 encoded, though,
while it was inside the envelope).  A lot of the meta-information in
the envelope (more of a packing crate, as things turned out, complete
with manifest and a spare wrench that the mechanic forgot) had to be
generated on the server side, by investigating certain attributes and
elements and text nodes, consulting other parts of the system, and
setting the appropriate values (it had to be done in order as well). 
So the model was a central "process" manager that took a document and
sent it off to the module responsible, for instance, for assigning
identity and ownership, got it back and sent it off to the module
responsible for insuring consistency, got it back and passed it off to
a module looked up in a namespace list for per-item specialized
processing, and finally handed it off to the persistence module. 
Depending on a flag, it might get it back from persistence.  At the
same time it handed it off to persistence, it also handed it off to an
analysis package, that looked at the internal content of the encoded
XML, related it to all the other things on the system, and persisted
more information in various related tables.

Each of the modules that did some processing worked basically
similarly: it had an adjunct that identified the bits it was interested
in, and the adjunct specified (in a module-specific fashion) what to
do.  "What to do" *usually* meant "if you find something matching this
XPath, go look at these three related pieces, and take one of these
eight (or eighteen, or eighty) resulting paths."

Queries worked similarly, except that the system allowed relatively
broadly phrased queries, with relatively "late" access checking.  That
is, it would look up all the things that you asked for, compose that
result into an XML document, then pass the document off to a module
that was capable of comparing the credentials of the user request with
the access control included in the results, which would simply prune
the tree of items that shouldn't be shown to that user.  Other
transformations were also performed; generally these were the result of
a "trigger" XPath (often on a text node, sometimes the content of an
attribute node, more rarely the existence of a particular element). 
Generally also, the called module had to do some additional checking
(in case you haven't tried it, debugging mnogo XPathov is a royal pain,
and the more complex, the worse the problem is).  Almost all of these
XPaths, of course, and especially the additional checks, could have
been rewritten into lovely, seven-line, baroque jewels of XPath
predicate-ry (but the underlying schemas were also in development
status, and maintaining this sort of XPath is equally frustrating labor
... *sigh* that no one has an "XPath compiler").

It would also have been possible to pass the Document itself, along
with the XPath, as a string ... that is, run the XPath once to check
the trigger, run it again to find the right location (and run more
XPaths to check things ...) ... our experience was that Java has more
type-safety, and we were far more competent with it, than XPath
expressions and evaluations.  We leveraged its use, but the ultimate
decision was that *good* XPaths (from the point of view of maintenance)
were simple, obvious ones, from a limited subset.  If we had to do
something like "select all element descendants with an id attribute
less than 5000 where there is a child element containing an id
reference in the range 400-700", then we'd select the element with an
id attribute, and go from there in Java (parameters encoded in the
adjunct, but not in the XPath).

Mind you, we did a *hell* of a lot of processing of things, and because
of the target market, we had to do *all* of it fast (or at least appear
to; we certainly did have to stay lightweight on each thread, 'cause we
had lots of 'em handling lengthy processes at once, potentially).  And
we were effectively using XML as a domain object, which (as Brett has
pointed out before on this list) is ... dumb.  Which was the informal
consensus among developers who survived (but don't tell management
...).  By project end, we had some far superior ways of handling
things, which weren't based in XML, but some areas *had* to stay XML,
because ... well, because XML *was* a valid domain object for us; we
were handling arbitrary XML documents, which we analyzed in some
interesting (and hopefully useful) ways.

So in some sense, this was an enterprise level XML document editing
application, and I think most folks are well aware that the standard
APIs aren't designed directly for editing (first principle of XML
parsers: if it isn't well-formed, die; first principle of an XML
editor: break the first principle of XML parsers when reading a
document ... you're supposed to help the user *fix* it, and dying isn't
helpful).  I don't expect that JDOM will directly support a lot of the
things that we did, but if JDOM were defined in a way that allowed easy
extensibility, then we could have based the obscure and dangerous
things that we did on its API, which is worlds less offensive and nasty
than DOM.  Or text-matching on XML as strings, which is a cardinal sin
against the gods of the XML forest.

Does that help?

The other reason I don't mention my company is because I'm
*notoriously* verbose; it ends up on my yearly evaluations.  *laugh*
To quote (or misquote) Voltaire, I am writing a long message, because I
do not have the time to write a short one.

Amelia A. Lewis          alicorn at mindspring.com          amyzing at talsever.com
How do you make a cat go moo?  Ask it: "Does a dog have the Buddha-nature?"

More information about the jdom-interest mailing list