开发者

can an XSD element be overloaded with multiple possible complex types?

开发者 https://www.devze.com 2023-03-17 16:02 出处:网络
I have a schema that defines an event record that is used to convey a message between two systems in a publish/subscribe scenario.The event includes a \"payload\" element, event_data, with the details

I have a schema that defines an event record that is used to convey a message between two systems in a publish/subscribe scenario. The event includes a "payload" element, event_data, with the details of the message. The complication is that the payload could be any of 30+ types, each defined in its own XSD.

For example (stripped down):

<event>
   <event_name>new_phone_number</event_name>
   <event_data>
      <areacode>303</areacode>
      <number>555-1212</number>
      <extension>31</extension>
   </event_data>
</event>

In this case, the event_data is of type phone_number, which is defined elsewhere in an imported XSD. But what I want to do is use the same mechanism to carry other kinds of structured message data. E.g., maybe it's a job change event, defined as type job_details:

<event>
   <event_name>new_job</event_name>
   <event_data>
      <job_title>CEO</job_title>
      <start_date>01/01/2012</start_date>
      <location>Main Office</location>
   </event_data>
</event>

The inner record, stored in the event_data element, is of type job_details, as defined in an imported XSD. The "outer" record, of type event, is little more than a way to carry the payload contained in the "inner" record.

So far I have looked at three ways to attack this, each with problems:

  1. Use a "choice" construct that lists all the possible record types. The problem seems to be that it's not natural xml/xsd to have all entries in the choice list share the same element name.

  2. I guess that rather than tr开发者_JS百科ying to include a structured subrecord in the event_data element, I could simply have an optional attribute reflecting every possible subrecord type. Each would have a unique name, of course, so you'd have an attribute for new_phone_number, one for new_job, and so on. Besides the potential maintainability and ugliness issues here, I'm not sure how I could enforce that one and only one of the attributes gets passed in a given instance of an event. I could live with that, but it makes the code fragile.

  3. Someone answered a similar question by suggesting use of a union - but that seems to apply only to simple types. Wouldn't cover my use case.

Stumped! Any guidance?


You can do this by using an xsi:type override in your instance document. XML processors cannot "infer" types, you need to provide this. Example:

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <event>
     <event_name>new_phone_number</event_name>
     <event_data xsi:type="PhoneNumberData">
        <areacode>303</areacode>
        <number>555-1212</number>
        <extension>31</extension>
     </event_data>
  </event>
</root>

Note that you have to define a base complex type EventData and PhoneNumberData must derive from this, for this to work.


In XSD 1.1 (implemented in Xerces and Saxon), you can do this using the feature called "conditional type assignment", whereby at the level of an element declaration you decide which type to use from a list of alternatives selected by applying an XPath expression to the element's attributes.


You could also look into using substitution groups although it doesn't probably suit your problem as well as the two previously suggested ones. Substitution groups are more like "using a specific element instead of a generic element" whereas your problem seems to be more something like "using a specific type instead of a generic type".

0

精彩评论

暂无评论...
验证码 换一张
取 消