views:

249

answers:

4
+2  Q: 

XML Reuse Question

In XML, is it possible to reuse elements?

Specifically, the problem that I am trying to solve is the following. I want to define an element table that contains an element tableSchema and an element dataSource. I want to do this in a way that a tables can refer to a tableSchema defined elsewhere. Thusly, I can have multiple reports defining tables according to the same tableSchema.

To clarify, I would like be able to do the following:

<report name="Report1">
  <page>
    <table>
      <!--reference to tableSchema named "foo"-->
      <dataSource>fooData</dataSource>
    </table>
  </page>
  <page>
    <table> 
      <!--reference to tableSchema named "bar"-->
      <dataSource>barData</dataSource>
    </table>
  </page>
</report>

and

<report name="Report2">
  <page>
    <table>
      <!--reference to tableSchema named "foo" (same as above!)-->
      <dataSource>anotherFooData</dataSource>
    </table>
  </page>
</report>

and have tableSchemas bar and foo defined elsewhere, possibly in the same XML document.

Edited to add: Here, by tableSchema, I do not mean another Xml schema. I mean a definition the fields in a table. For example, I would like to be able to do the following:

<tableSchema name="bar">
    <field>
      <displayName>bar1</displayName>
      <sourceName>bar1Source</sourceName>
      <format>Currency</format>
    </field>
    <field>
      <displayName>bar2</displayName>
      <sourceName>bar2Source</sourceName>
      <format>Text</format>
    </field>
</tableSchema>

<tableSchema name="foo">
    <field>
      <displayName>foo1</displayName>
      <sourceName>foo1Source</sourceName>
      <format>Percent</format>
    </field>
</tableSchema>

Then, in the above, Report1 defines a report that contains two tables, one formatted according to the tableSchema foo, and a second formatted according to the tableSchema bar, and Report2 defines a report that contains one table that is formatted according to the tableSchema foo and that schema is the same as in Report1.

A: 

You might have to use a XSL stylesheet transformation to do what you want. In the end it will result in a complete and resolved XML.

Otávio Décio
+2  A: 

You didn't provide context as to what would be creating/parsing this XML but assuming you have control over this then you could define your own convention for this eg:

<tableSchema ref="foo">

Where the parser would then look for a element with the id of "foo" to retrieve the tableSchema info.

Marplesoft
...then look for a element with the ID "foo"...
Javier
I'll be reading the document with a plain ol' .NET XmlReader.
Jason
I effectively took your idea to solve by problem. I added a tag `externalSchema` with attribute `location` and when the parser stumbles upon one of these tags it opens another `XmlReader` to parse the file at `location` to read in the table schema. This gave me the reuse that I was looking for. Thanks.
Jason
+1  A: 

Why not just include the definition? You define it in one XML Schema, then include it wherever you want to use it in another XML Schema, like this:

<include schemaLocation="http://www.example.com/schemas/barDef.xsd"/&gt;
<include schemaLocation="http://www.example.com/schemas/fooDef.xsd"/&gt;

There's a second aspect to your question: for the XML document to be able to specify which kind of tableSchema it is.

Here's an analogy with OO programming: (1) define a superclass, (2) define foo and bar as subclasses of it. Then, (3) define the type of a field to be of their common superclass; and now (4). a runtime object can of either subclass. Does that make sense? I think it's what you're thinking in terms of anyway.

To complete the analogy: in XML, a class is a complexType; a subclass is an extension of it; a field is an element and it's class is its type attribute - and the class of a runtime object is the xsi:type of an element in an XML document. The crucial thing is that last part, xsi:type.

(1). Define the common super class - an XML complexType:

<complexType name="MySuperType">
  ...
</complexType>

(2). Define the subclasses - extensions of the above complexType:

<complexType name="Foo">
  <complexContent>
    <extension base="MySuperType">
      ...
    </extension>
  </complexContent>
</complexType>

<complexType name="Bar">
  <complexContent>
    <extension base="MySuperType">
      ...
    </extension>
  </complexContent>
</complexType>

(3). Define a field to be of the superclass - an element to be of the complexType extended from:

<element name="tableSchema" type="mySuperType"/>

(4). Now the XML can specify that an element is of a particular complexType in the XML itself:

<report xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
  <page>
    <table>
      <tableSchema xsi:type="foo"/>
      <dataSource>fooData</dataSource>
    </table>
  </page>
  <page>
    <table> 
      <tableSchema xsi:type="bar"/>
      <dataSource>barData</dataSource>
    </table>
  </page>
</report>

Note that type is special, and is defined in the namespace given. In fact, there are several namespace issues that can be frustrating, but the key thing is that it is possible to do what you want.

For a more complete example, please see the XML Schema Primer.

13ren
I believe there is some confusion here, and it's my fault for introducing it by using the term "schema" in reference to "tableSchema." I think it would have been more clear had I said "tableDefinition" and elaborated that it defines the fields that are visible in a table in a report. I'll edit the original post to make this more clear.
Jason
A: 

(I might not understand the question yet, but...) Assuming you want to use the text values in the tableSchema literally, then it's really up to your processing code. The XML is just the representation of the data. So you could make up your own format, like this say:

<tableSchema ref="foo"/>

Then your tool reads the whole document, and remembers the definitions of foo and bar (in a table). Then, it starts to process the Reports: when it goes to use Report1, and it see the above ref to foo, it looks up foo in the hash table and uses that. Is that the kind of thing you mean?

If so, there is a little more support for this with using ID and IDREF tags, so you have this:

<tableSchema myidref="foo"/>

<tableSchema myid="foo">
    <field>
      <displayName>foo1</displayName>
      <sourceName>foo1Source</sourceName>
      <format>Percent</format>
    </field>
</tableSchema>

Then, (I think) the parsing tool will populate and lookup the table for you. You need to define myidref and myid as of type IDREF and ID in the Schema/DTD, so the parser knows to treat them specially. Something like (just showing myidref):

<element name="tableSchema">
  <complexType>
    <xsd:attribute name="myidref" type="xsd:IDREF" use="required"/>
  </complexType>
</element>
13ren