可以使用多种可能的复杂类型重载XSD元素吗?

时间:2011-07-06 23:36:38

标签: xml xsd

我有一个模式,用于定义事件记录,该记录用于在发布/订阅方案中的两个系统之间传递消息。该事件包括“payload”元素 event_data ,以及消息的详细信息。复杂的是,有效载荷可以是30多种中的任何一种,每种类型都在其自己的XSD中定义。

例如(剥离):

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

在这种情况下, event_data 的类型为 phone_number ,这是在导入的XSD中的其他位置定义的。但我想要做的是使用相同的机制来携带其他类型的结构化消息数据。例如,可能是工作变更事件,定义为 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>

存储在 event_data 元素中的内部记录的类型为 job_details ,如导入的XSD中所定义。 事件类型的“外部”记录只不过是一种携带“内部”记录中包含的有效负载的方式。

到目前为止,我已经研究过三种攻击方式,每种方法都有问题:

  1. 使用“choice”结构列出所有可能的记录类型。问题似乎是,选择列表中的所有条目共享相同的元素名称不是自然的xml / xsd。

  2. 我想这不是试图在 event_data 元素中包含结构化子记录,而是可以简单地使用一个可选属性来反映每个可能的子记录类型。当然,每个都有一个唯一的名称,因此你有 new_phone_number 的属性, new_job 的属性,依此类推。除了潜在的可维护性和丑陋问题之外,我不确定如何强制执行该操作,并且在给定的事件实例中只传递一个属性。我可以忍受,但它使代码变得脆弱。

  3. 有人通过建议使用联合回答了类似的问题 - 但这似乎只适用于简单类型。不会涵盖我的用例。

  4. 难倒!任何指导?

3 个答案:

答案 0 :(得分:1)

您可以在实例文档中使用xsi:type覆盖来执行此操作。 XML处理器无法“推断”类型,您需要提供此类型。例如:

<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>

请注意,您必须定义基本复杂类型EventData,并且必须从此PhoneNumberData派生,才能实现此目的。

答案 1 :(得分:1)

在XSD 1.1(在Xerces和Saxon中实现)中,您可以使用名为“条件类型赋值”的功能执行此操作,从而在元素声明的级别,您可以从通过应用选择的备选列表中确定要使用的类型对元素属性的XPath表达式。

答案 2 :(得分:0)

你也可以考虑使用substitution groups虽然它不太适合你的问题以及之前提出的两个问题。替换组更像是“使用特定元素而不是通用元素”,而您的问题似乎更像是“使用特定类型而不是泛型类型”。