Title: RE: [castor-dev] Unmarshalling unknown java

Steve,

I've had to address a problem similar, if not identical,
to what you are describing.  I have a schema that defines
an element which, in turn, contains instances of other
elements.  In any given XML instance document I know that
exactly one of these "contained" elements will be populated.
The schema looks something like:

<element name="container">
 <complexType>
  <sequence>
   <element name="member1" type="someType1" minOccurs="0"/>
   <element name="member2" type="someType2" minOccurs="0"/>
   .             .              .            .         .
   <element name="memberN" type="someTypeN" minOccurs="0"/>
  </sequence>
 </complexType>
<element>

What I'm really trying to define here is a <choice> relationship,
but I have not been able to get <choice> in Castor to work
properly.  Hence, I've resorted to appending minOccurs="0" to
all the contained elements-- not the same effect as <choice>,
but close enough (at least for my purposes).

So, once you have unmarshalled an XML instance, how do you determine
which "contained" element is actually populated.  The key is to
examine the object tree that Castor creates from the XML.  What you
end up with is a Container object that holds private member
references that represent each of the contained elements-- Member1,
Member2, ...MemberN.  It also provides a "getter" method for each
of these.  Given this arrangement you could simply have a big
if statement such as:

String getContainedElementName(Container c)
{
  Object res = null;
  if ((res = c.getMember1()) != null)
    return res.getClass().getName();
  else if ((res = c.getMember2()) != null)
    return res.getClass().getName();
  .    .      .       .       .    .
  else if ((res = c.getMemberN()) != null)
    return res.getClass().getName();
  else
    return res;
}

But this is pretty ugly.  Plus, if you ever want
to add/modify/delete any "contained" elements, you've
got to modify the code as well.

A better approach, at least from the standpoint of
maintenance, is to use reflection to query the container
object for all of its "getter" methods.  Then invoke each
in turn until you get a non-null result:

String getContainedElementName(Container c)
{
  Class cl = c.getClass();
  Method[] meths = cl.getMethods();
  String mName = new String("");
  try
  {
    for (int i = 0; i < meths.length; i++)
    {
      mName = meths[i].getName();
      if (mName.startsWith("get"))
      {
        Object o = meths[i].invoke(c, null);
        if (o != null)
          return o.getClass().getName();
      }
    }
  }
  catch (Exception e)
  {
    // invoke() may throw one of several exceptions
  }
  return null;
}

This approach frees you from the burden of keeping the
Java code in-sync with the schema.  The downside is that
the reflection is somewhat expensive.  How much so depends
to a large extent on the quantity of "contained" elements
you're dealing with.  I'd sure like to hear about other
approaches folks on this list may have employed.

Hope this helps.

Regards,

Pete



-----Original Message-----
From: S.H.Kinder [mailto:[EMAIL PROTECTED]]
Sent: Wednesday, November 14, 2001 6:32 PM
To: [EMAIL PROTECTED]
Subject: [castor-dev] Unmarshalling unknown java


Apologies if this is off the development thread or a dumb question. I'm
new to castor and am investigating whether it can do the job for me.
It seems a good way to extract data from xml in principle.

I have succeeded in defining some simple xml and schema to allow me
to unmarshal a known object type from the xml. However what if the xml
might define one of a list of possible java objects, defined via the
schema. How can I unmarshal into a java Object, so that I can then
test the Object class and act accordingly? If someone could provide
an example and/or advice this would be much appreciated.

Cheers

Steve

-----------------------------------------------------------
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
        unsubscribe castor-dev

Reply via email to