[xsd-users] How to know the member functions at run time

Boris Kolpackov boris at codesynthesis.com
Sun Apr 2 05:55:19 EDT 2006


Hi Yongsheng,

Zhao, Yongsheng <yongsheng.zhao at nortelgov.com> writes:

> Say, I have a Task class which is generated by xsd from xml schema. But
> I don't know what exactly in this class, due to this class varies from
> applications. Then I need call the member functions of this class. Is
> there a way to do it at run time? Does xsd provide this kind of functions?

There is no way to do it completely dynamically, i.e., without any prior
knowledge about the Task type. If, however, you know all the possible
Task types before you compile your code then you can create a set of
thunks that will allow you to call a member function generically on
one of those Task instances. Suppose you have the following two Task
types:

<xsd:simpleType name="Priority">
  <xsd:restriction base="xsd:unsignedInt"/>
</xsd:simpleType>

<xsd:complexType name="Task1">
  <xsd:sequence>
    <xsd:element name="priority" type="Priority"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Task2">
  <xsd:sequence>
    <xsd:element name="priority" type="Priority"/>
  </xsd:sequence>
</xsd:complexType>


xsd will generate C++ code like this:


struct Task1: xml_schema::type
{
  Priority
  priority () const;

  ...
};

struct Task2: xml_schema::type
{
  Priority
  priority () const;

  ...
};

Let's say you you have a reference to xml_schema::type which you know
is actually one of the Tast types and you want to call priority().
The right solution for this problem would be to factor out priority
into the common TaskBase type and inherit both Task1 and Task2 from
it. I assume this solution is not available to you for some reason.

The next easiest way would be to do something like this:

Priority
task_priority (xml_schema::type const& task)
{
  Priority p (0);

  if (Task1 const* t1 = dynamic_cast<Task1 const*> (&task))
  {
    p = t1->priority ();
  }
  else if (Task1 const* t2 = dynamic_cast<Task2 const*> (&task))
  {
    p = t2->priority ();
  }
  else
  {
    // error
  }

  return p;
}

If you do not want to pollute your code with all those if's then
you can create a thunk table, e.g.:

#include <map>
#include <typeinfo>


template <typename Task>
Priority
priority_thunk (xml_schema::type const& task)
{
  return dynamic_cast<Task const&> (task)->priority ();
}

typedef Priority (*PriorityThunk) (xml_schema::type const& task);
typedef std::map<std::type_info, PriorityThunk> PriorityThunkMap;
PriorityThunkMap priority_thunk_map;


Priority
task_priority (xml_schema::type const& task)
{
  priority_thunk_map[typeid (task)] (task);
}

int
main ()
{
  // Initialize priority_thunk_map.
  //
  priority_thunk_map[typeid (Task1)] = &priority_thunk<Task1>;
  priority_thunk_map[typeid (Task2)] = &priority_thunk<Task2>;
}

Finally, if you really have no way of knowing all the Task types
before you compile your code (e.g., you load them dynamically
at runtime) then the only solution that I can think of is to
skip calling member function altogether and instead obtain a
DOM node corresponding to the Tast instance, use DOM iteration
methods to find a DOM node that corresponds to the element with
the name "priority", and, finally, go back to a tree node:

#include <xercesc/dom/DOM.hpp>
#include <xsd/cxx/xml/string.hxx> // Keeps us sane when working with Xerces.

using namespace xercesc;
namespace xml = xsd::cxx::xml;

Priority
task_priority (xml_schema::type const& task)
{
  xml_schema::type& task = ...
  DOMNode const* task_node (task._node ());
  DOMNode const* priority_node (0);

  for (DOMNode const* n (root->getFirstChild ());
       n != 0;
       n = n->getNextSibling ())
  {
    if (n->getNodeType () == DOMNode::ELEMENT_NODE &&
        xml::transcode<char> (n->getLocalName ()) == "priority")
    {
      priority_node = n;
      break;
    }
  }

  if (priority_node != 0)
  {
    // Get back to a tree node from the DOM node.
    //
    xml_schema::type& t (
      *reinterpret_cast<xml_schema::type*> (
        priority_node->getUserData (xml_schema::tree_node_key)));

    Priority& p (dynamic_cast<Priority&> (t));
    return p;
  }
  else
  {
    // Error: this task does not have the priority element.
  }
}

One thing to note about this approach is that the back reference from
DOM nodes to tree nodes has been added after the 2.0.0 release so you
will need to update your installation. See this post for more information:

http://codesynthesis.com/pipermail/xsd-users/2006-March/000274.html

This will also be included in the upcoming 2.1.0 release.

hth,
-boris
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 652 bytes
Desc: Digital signature
Url : http://codesynthesis.com/pipermail/xsd-users/attachments/20060402/455b1559/attachment.pgp


More information about the xsd-users mailing list