OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

 


 

   Re: Wish list for XMLApplication Framework

[ Lists Home | Date Index | Thread Index ]
  • From: Tyler Baker <tyler@infinet.com>
  • To: Dmitri Kondratiev <dima@paragraph.com>
  • Date: Thu, 12 Mar 1998 10:43:08 -0500

Dmitri Kondratiev wrote:

> The following are some of the features I'd like to be able to use in
> XMLApplication Framework :
>
> - Support for both, event-based and tree-based parsers, to serialize XML
> elements to application-specific element-objects.
> Tree-based approach is certainly cleaner when you need to parse document as
> a whole, but, imagine, in my appl. I may need to stop parsing relatively big
> document in the middle, when I come across some element. So I don't need the
> whole tree! And still I may need to instantiate my appl. specific
> element-objects.
>
> - Runtime configuration of "element-semantic" handlers.
> Ideally I'd like to be able to switch element-semantic handlers in run-time.
> This might seem nonsense first, but if you give this idea a second thought
> you'll see the point. XML is very wise to **not imply element semantic**, so
> it may be useful for some app. (such as mine) to be able to switch one or
> more times when processing a document from one set of element-objects to
> another. In other words the ability to bind different semantic-handlers (and
> thus element-objects) to elements in runtime is needed. Naming handler in
> the XML document will allow to start parsing with some general
> "semantic-switch" handler, that will activate different semantic-handlers as
> needed.

I already have a solution to this in a parser/formatter I have written for my
application.  The parser is non-validating and is very far from being something a
third party could really use.  But it works great (despite its lack of speed at
the moment) for my application.  There is an XMLReader and an XMLWriter.  The
parser of course is the reader and the formatter is of course the writer.  These
two classes are sublasses of java.io.Filter*Reader.

> - Basic support for element-object to element markup serialization. This
> will allow application to modify element-object in runtime and then
> serialize it **in application-specific way** back in markup representation
> by means of XMLDataOutputStream stream connected to XML document instance.

I do this already be their being a root element (the document) and when the
parser comes across a start element tag or an empty element tag, the the Element
object (handler) is queried at run-time for a a sub-element or other object
handler like a PI.

This is the following interface I have now for Element.  It should give you a
good idea of what is going on.

package com.dais.populous.util.xml;

public interface Element {
  String getElementName();

  // Attribute forAttributeName(String attributeName, int type, int index);
  void setElementAttributes(Attribute[] attributes);
  // may return null
  Attribute[] getElementAttributes();

  // Returns a child element given an element name and content index
  Element forElementName(String elementName, int index);
  // Returns a processing instruction for this element given a target application

  // name and content index.
  ProcessingInstruction forProcessingInstructionTarget(String target, int index);

  void setElementCharacterData(String data, int index);

  // may return null
  Object[] getElementContent();
}

Since this is an interface, you can have each of your objects implement this
interface (or subclass an Adapter class) in your object graph and for objects
that are final and cannot be sublassed like InetAddress, you can write an
anonymous inner class to handle this type of object.  Here is some code from my
actual application.  Note: the bounds object should probably utilize four
attributes rather than 4 subelements, but in my DTD I happen to use this right
now for completeness.  All of these methods are from a class I call Capsule.  A
parent model class which acts as a Document and contains "Capsules" also
implements Element so you can easily initialize/save objects with this method.

  public void format(OutputStream out) {
    try {
      XMLWriter writer = new XMLWriter(new OutputStreamWriter(out), "  ");
      writer.writeDocument(this, "capsule.dtd");
      writer.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
  }

  public String getElementName() {
    return "capsule";
  }

  public Object[] getElementContent() {
    byte[] data = getComponentData();
    Object[] content = new Object[3 + ((data != null) ? 1 : 0)];

    content[0] = capsuleEntry;
    content[1] = new BasicElement("component-name", componentName);
    content[2] = new BoundsElement();
    if (data != null) content[3] = new BasicElement("component-data",
DataUtil.encoder.encodeBuffer(data));

    return content;
  }

  public void parse(InputStream in) {
    try {
      XMLReader reader = new XMLReader(new InputStreamReader(in));
      reader.readDocument(this);
      in.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
  }

  public Element forElementName(String elementName, int index) {
    if (elementName.equals("capsule-entry")) {
      capsuleEntry = new CapsuleEntry();
      return capsuleEntry;
    }
    else if (elementName.equals("component-name")) {
      return new AbstractElement() {
        public String getElementName() {
          return "component-name";
        }

        public void setElementCharacterData(String data, int index) {
          componentName = data.trim();
        }
      };
    }
    else if (elementName.equals("bounds")) {
      return new BoundsElement();
    }
    else if (elementName.equals("component-data")) {
      return new AbstractElement() {
        public String getElementName() {
          return "component-data";
        }

        public void setElementCharacterData(String data, int index) {
          try {
            setComponentData(DataUtil.decoder.decodeBuffer(data.trim()));
          } catch (IOException e) {
              e.printStackTrace();
          }
        }
      };
    }
    return null;
  }

  public void setElementAttributes(Attribute[] attributes) {}
  public Attribute[] getElementAttributes() {return null;}
  public ProcessingInstruction forProcessingInstructionTarget(String target, int
index) {return null;}
  public void setElementCharacterData(String data, int index) {}

  class BoundsElement extends AbstractElement {
    public String getElementName() {
      return "bounds";
    }

    public Object[] getElementContent() {
      Object[] content = new Object[4];

      Rectangle bounds = getBounds();
      content[0] = new BasicElement("x", String.valueOf(bounds.x));
      content[1] = new BasicElement("y", String.valueOf(bounds.y));
      content[2] = new BasicElement("width", String.valueOf(bounds.width));
      content[3] = new BasicElement("height", String.valueOf(bounds.height));

      return content;
    }

    public Element forElementName(String elementName, int index) {
      if (elementName.equals("x")) {
        return new AbstractElement() {
          public String getElementName() {
            return "x";
          }

          public void setElementCharacterData(String data, int index) {
            Rectangle bounds = getBounds();
            bounds.x = Integer.parseInt(data.trim());
            setBounds(bounds);
          }
        };
      }
      else if (elementName.equals("y")) {
        return new AbstractElement() {
          public String getElementName() {
            return "y";
          }

          public void setElementCharacterData(String data, int index) {
            Rectangle bounds = getBounds();
            bounds.y = Integer.parseInt(data.trim());
            setBounds(bounds);
          }
        };
      }
      else if (elementName.equals("width")) {
        return new AbstractElement() {
          public String getElementName() {
            return "width";
          }

          public void setElementCharacterData(String data, int index) {
            Rectangle bounds = getBounds();
            bounds.width = Integer.parseInt(data.trim());
            setBounds(bounds);
          }
        };
      }
      else if (elementName.equals("height")) {
        return new AbstractElement() {
          public String getElementName() {
            return "height";
          }

          public void setElementCharacterData(String data, int index) {
            Rectangle bounds = getBounds();
            bounds.height = Integer.parseInt(data.trim());
            setBounds(bounds);
          }
        };
      }
      return null;
    }
  }

The nicest thing about this approach is that if there is an element the Element
handler cannot handle, then null is returned and the parser simply ignores all
subelements of that element.  This is like ignoring all the stuff in between the
Applet Tag if a browser cannot understand it.  Also, since Element handlers are
returned by reference, you don't need to instantiate special objects to wrap the
XML data like you would if you built a tree based model of the XML data.  Of
course using this approach you could still easily build a big old tree if you
wanted to.

Regards,

Tyler


xml-dev: A list for W3C XML Developers. To post, mailto:xml-dev@ic.ac.uk
Archived as: http://www.lists.ic.ac.uk/hypermail/xml-dev/
To (un)subscribe, mailto:majordomo@ic.ac.uk the following message;
(un)subscribe xml-dev
To subscribe to the digests, mailto:majordomo@ic.ac.uk the following message;
subscribe xml-dev-digest
List coordinator, Henry Rzepa (mailto:rzepa@ic.ac.uk)





 

News | XML in Industry | Calendar | XML Registry
Marketplace | Resources | MyXML.org | Sponsors | Privacy Statement

Copyright 2001 XML.org. This site is hosted by OASIS