Hey Thomas

From: "Thomas Nichols" <[EMAIL PROTECTED]>
> >Yes I think returning the Element when adding text or entities sounds a
good
> >idea.
> >Though the addElement() returns the new Element child rather than the
parent
> >so care should be taken with nestings.
>
> Ah - this is not what I'd been thinking of. So
> foo.addEntity ("bar"); // returns foo
> foo.addElement ("bar"); // returns ref to the new bar Element ?? I'd
> expected it to return foo.

Thats right. But there's a reason for that. It allows the addElement() to be
a factory method, returning the new element for further customisation
without having to explicitly use the DocumentFactory or to hard code any
implementation class names in your code.

It allows documents to be build up (albeit in a more verbose manner than the
one you suggest) as follows:-

DocumentFactory factory = DocumentFactory.getInstance();
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement( "root" );
Element first = root.addElement( "first" );
Element second = root.addElement( "second" ).setAttributeValue( "currency",
"GBP" );
Element amount = root.addElement( "amount" ).addText( "100" );

The above would create a Document with some elements without any
implementation class being mentioned in code. (So it avoids referring to
DefaultElement explicitly).

Using the "org.dom4j.factory" system property we could have changed the
exact DocumentFactory implementation used in the above code and so affected
the exact Element implementations used. (For example we might have used some
special schema based DocumentFactory which knows that the <amount> element
is an Integer).

So I'd like to keep this simple syntax if we can as it hides the use of the
DocumentFactory and hides implementation details too. But I'd also like to
support the kind of 'Element Construction Set' like syntax you're using.

So for example, to make the XML document :-.

<complexType mixed="true">
     <sequence>
         <element ref="xyz" />
     </sequence>
</complexType>

You could use:-

Document doc = DocumentHelper.createDocument();
Element complexType = doc.addElement( "complexType" ).setAttribute( "mixed",
"true" );
Element sequence = complexType.addElement( "sequence" );
Element element = sequence.addElement( "element" ).setAttribute( "ref",
"xyz" );

Thats fairly concise, plus it allows exact elements to be further customised
later if required using instance variables when doing loops or conditional
logic. It could be condensed a little as follows:-

Document doc = DocumentHelper.createDocument();
doc.addElement( "complexType" ).setAttribute( "mixed",
"true" ).addElement( "sequence" ).addElement( "element" ).setAttribute(
"ref", "xyz" );

Though I tend to favour the former as its easier to read. (Also it might be
easier to just parse a text file ;-)


It may be quite confusing for users, but we could let the add() method
return a reference to the Element on which the node was added since its not
acting as a factory method as you pass in the node you wish to add.
Contrast:-

    // create a new element, add it and return a reference
    Element child = parent.add( "child" );

with

    // create a new element
    Element child = factory.createElement( "child" );
    // add the element
    parent.add( child );.

In the latter, the program knows what the child reference is, so the
add(Element) method could return the self (parent).

So your example:-

    Element complexType = new DefaultElement ("complexType") . add (new
    DefaultAttribute ("mixed", "true"))
         .add (new DefaultElement ("sequence")
               .add ((new DefaultElement ("element") . add (new
    DefaultAttribute ("ref", "xyz")))));

Could be written (using a factory rather than using concrete implementation
classes):-

    DocumentFactory factory = DocumentFactory.getInstance();

    Element complexType
        = factory.createElement( "complexType" )
            .setAttributeValue( "mixed", "true" )
            .add(
                 factory.createElement( "sequence" )
                    .add(
                        factory.createElement( "element" )
                            .setAttributeValue( "ref", "xyz" )
                    )
            );

This is quite similar to your example but using the factory.

One added complication if we did go this way is that we've tried to make
Document and Element polymorphic such that they both extend the Branch
interface. So that adding ProcessingInstruction, Comment and Element might
need to return Branch rather than Element which might require some casting.

Maybe the add(Element), add(ProcessingInstruction) and add(Comment) should
move from Branch into both Document and Element such that they can return
Document or Element as the return type and leaving only add(Node) which can
be called polymorphically from Branch (and would return an instance of
Branch).

So then we could treat a Document in a similar way as:-

    Document doc
        = factory.createDocument()
            .addComment( "start of document" )
            .setDocType( "complexType", "my public ID", null )
            .add(
                 factory.createElement( "complexType" )
                    .setAttributeValue( "mixed", "true" )
                    .addComment( "inside the complexType element" );
                    .add(
                         factory.createElement( "sequence" )
                            .add(
                                factory.createElement( "element" )
                                    .setAttributeValue( "ref", "xyz" )
                            )
                    )
            )
            .addComment( "end of document" );


This syntax does help with "mixed content" type situations (e.g. look at the
second paragraph)...

Element html
    = factory.createElement( "html" )
        .add(
            factory.createElement( "head" )
                .add(
                    factory.createElement( "title" )
                        .addText( "this is the title" )
                )
        )
        .add(
            factory.createElement( "body" )
                .add(
                    factory.createElement( "h1" )
                        .addText( "title #1" )
                )
                .add(
                    factory.createElement( "p" )
                        .addText( "this is paragraph #1" )
                )
                .add(
                    factory.createElement( "p" )
                        .addText( "this is paragraph #2 " )
                        .add(
                            factory.createElement( "b" )
                                .addText( "bold" )
                        )
                        .addText( " more text" )
                )
        );

Though it is easier when just writing this as text ;-)

<html>
    <head>
        <title>this is the title</title>
    </head>
    <body>
        <h1>title #1</h1>
        <p>this is paragraph #1</p>
        <p>this is paragraph #2 <b>bold</b> more text</p>
    </body>
</html>


Does this approach appeal? Any thoughts?

James



_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com


_______________________________________________
dom4j-dev mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/dom4j-dev

Reply via email to