6

I am attempting to generate c# classes from schemas provided by the FHIR project: http://hl7.org/implement/standards/fhir/ I have downloaded the schemas: http://hl7.org/documentcenter/public/standards/FHIR/fhir-all-xsd.zip I have "Unblocked" the zip file and unzipped the xsd files into a folder. While attempting to use xsd.exe to create c# classes, I keep getting errors that indicate an issue with the schemas. Consistently getting xhtml:div element is not declared in addition to others. The file fhir-all.xsd seems to list the top level objects. I was able to get the simple schema tombstone.xsd to work with xsd.exe, but a more complex item like valueset.xsd or alert.xsd fails miserably. I can't see what is wrong with these files. Any help on how to fix these schemas will be appreciated.

jlo-gmail
  • 4,453
  • 3
  • 37
  • 64
  • Are you including the chain of .xsd files in the xsd.exe command? – Popo Feb 18 '14 at 18:40
  • not sure what that means. most of the xsd files seems to have include elements that refer to files in the set, especially to the elements xsd.exe says are missing. – jlo-gmail Feb 18 '14 at 18:59
  • I had a similar issue and had to tell xsd.exe all the files names that were referenced in the xsds, just throwing that out there, it may not be your issue. – Popo Feb 18 '14 at 19:22
  • There are bigger issues with the schema set you've referenced... To help me understand the kind of answer I should provide, are you a professional user, or simply trying to learn/understand XSD in general, HL7 in particular? – Petru Gardea Feb 18 '14 at 20:18
  • I am a .Net developer and my intention is to create c# classes from these schemas. I want simple POCO's OR LINQ enabled datasets, so I an not interested in the FIHR .Net download. – jlo-gmail Feb 18 '14 at 21:54

4 Answers4

6

Generating POCO's from the XSD's will give less-then-optimal classes however. Since FHIR's serialization avoids the use of polymorhism, elements that present a choice (e.g. Observation.value) will be represented in the XSD as sets of elements with identical names (valueNumber, valueString, valueCodeableConcept etc. etc).

As well, it's pretty hard to use the same POCO's for json serialization.

In the .NET NuGet package for FHIR, you'll find a set of generated classes for the FHIR Resources, which are as light-weight as I could make them. In addition, there are Validation attributes to validate their contents, the package contains serializers and parsers for json and xsd and a REST client to invoke the rest operations on a server.

If you need to integrate the parsers and serializers with WebAPI, I have posted about that here: HL7 FHIR serialisation to json in asp.net web api

Community
  • 1
  • 1
Ewout Kramer
  • 984
  • 6
  • 9
  • Nice try :)... For a sidebar I would've asked why the `I am not interested in the FIHR .Net download.` comment to begin with... – Petru Gardea Feb 19 '14 at 15:09
  • It seems to me the Fhir schemas have problems that can be easily corrected: 1-remove the dependency on xhtml1-strict.xsd - this schema has circular references preventing classes from being created. 2- remove the use of choice elements in the schema. These lead to types defined as objet that can be a list of things. The real problem I see with the spec to far is this idea that the "documentation" will inform the developer as to the structures. Documentation is ALWAYS missing, incomplete, out-of-date, wrong. The only reliable documentation in a system like this is the schemas. – jlo-gmail Mar 03 '14 at 16:13
  • Hi jlo, please note that in the FHIR spec, the schemas are actually generated from the same source as the documentation, so the schemas are also a derivative, not the source. The schemas are not maintained by hand! The publication tool generates the website from the design source, generates the schemas and then validates the examples. The source code for .net and java are also generated, so always up-to-date! – Ewout Kramer Mar 24 '14 at 13:55
2

First, you need to understand that the FHIR XSD files describe two identical XML Schema sets: a "verbose" one, that maintains the logical packaging of the standard (and it uses a lot of <xsd:include>), and a "single" one, where for interoperability reasons, it does not use include directives i.e. all the content targeting a particular namespace goes in one XSD file.

These are the two sets, you need to use only one. The verbose set:

enter image description here

... and the "single file per namespace" one:

enter image description here

As I've explained in this post, you should refer to the "single one" set. Unlike that post, you don't need another tool to collapse all these XSD files, you are given the "single" set.

Build the command line traversing the second diagram, top to bottom, left to right, and you should get rid of all the problems related to undefined content.

This is where you run into what some call a limitation in xsd.exe, regarding support for circular group references. Microsoft says it is not (here and here at least); both XSD 1.0 spec and XSD 1.1 spec read that

There are no circular groups. That is, within the {particles} of a group there is no particle at any depth whose {term} is the group itself.

The interpretation of the above in what xsd.exe uses, causes the problem. The xhtml1-strict.xsd file is riddled with "circular group" dependencies. You'll not be able to escape those errors using xsd.exe unless you fix that file (we did it for a client once) or modify references to any xhtml content along the same lines the FHIR library seems to deal with HTML markup. The latter approach is more consistent with that view where one should not generate code bindings for HTML markup due to its mixed content nature, which make it useless (at least there's no roundtrip possible, nor correct reading of the text nodes) in all the code binding technologies I could think of, including .NET's serialization.

Given @GrahameGrieve's second comment, I should've pointed out explicitly that .NET's built in XSD processor correctly validates the XHTML schema. So this is not a .NET XSD processor issue, but rather an issue in other parts of the .NET which xsd.exe relies on (to be even more specific, it is an external call xsd.exe makes, XmlSchemaImporter.ImportTypeMapping which fails miserably)

This one I would blame the spec for not being clearer, to avoid this kind of confusion which in my opinion is partly to blame for having a mainstream product misbehaving.

Community
  • 1
  • 1
Petru Gardea
  • 21,373
  • 2
  • 50
  • 62
  • "You'll not be able to get rid of those errors unless you fix that file (we did it for a client once)" - can you clarify? a div can contain a div. I don't know how to fix the file and still describe valid xhtml? – Grahame Grieve Apr 11 '14 at 21:36
  • Regarding the note in the XSD spec, this is not being interpreted correctly here - see http://lists.w3.org/Archives/Public/xmlschema-dev/2007Mar/0032.html – Grahame Grieve Apr 11 '14 at 22:27
  • @GrahameGrieve, thank you for bringing these references; I've clarified my answer. Michael's reply is related to a test case that works correctly with xsd.exe. Regarding your first comment, I am not sure I understand the div part; as for fixing, you only have to do it if your solution relies on XmlSchemaImporter. We're specialized in XML Schema Refactoring, so as a service to our customers running in syntax not supported by their tools (as it happens here with xhtml1-strict.xsd and xsd.exe), we release **equivalent** XSDs (internal use) without the troublesome bits. – Petru Gardea Apr 12 '14 at 13:52
  • How could the spec be clearer? I suppose we could add a note: "don't use xsd.exe because it's dumb". And I still don't understand how you can have an equivalent schema that isn't a problem for xsd.exe. Presumably you're not going to clarify... – Grahame Grieve Apr 12 '14 at 20:04
  • @GrahameGrieve, are we talking about the same spec here? I refer to the W3C XML Schema spec (XSD) - since the interpretation of that is what causes issues with xsd.exe, not the FHIR standard (you seem to be associated with). The fix I am referring to is the xhtml1-strict XSD, not your OTHER schemas. If you're interested in an XSD for xhtml1-strict that does not uses groups, yet it validates the same, feel free to contact me directly through the support address on my website. – Petru Gardea Apr 12 '14 at 21:04
  • (cont'd)... and yes, adding a note for users that might be using xsd.exe, is a good idea: many people still rely on this particular tool so it might simply save some support time on your end to pre-empt the post we've gathered around. – Petru Gardea Apr 12 '14 at 21:23
2

So far I have been able to generate classes and de-serialize many of the patient*.xml samples provided to both raw classes generated as described, and classes generated from the raw classes by a SOAP service.

Editing xhtml1-strict.xsd to fix this issue is not that simple. I used xsd.exe to attempt to create classes from the file, then used the error messages as starting points. After some experimentation, I cam up with this file. It addresses the problem with the div element, as long the HTML contained is kept simple. I am sharing the difference report for others to make use of. The numbers represent line-number. (I am just sharing the changes because of size limitations, I tried to share the whole file).

XSD\xhtml1-strict.xsd(413):      <!--<xs:group ref="inline"/>-->
XSD\xhtml1-strict.xsd(441):      <!--<xs:element ref="pre"/>-->
XSD\xhtml1-strict.xsd(443):      <!--<xs:element ref="blockquote"/>-->
XSD\xhtml1-strict.xsd(462):      <!--<xs:group ref="misc"/>-->
XSD\xhtml1-strict.xsd(519):      <!--<xs:group ref="block"/>-->
XSD\xhtml1-strict.xsd(520):      <!--<xs:group ref="misc"/>-->
XSD\xhtml1-strict.xsd(539):      <!--<xs:group ref="misc"/>-->
XSD\xhtml1-strict.xsd(1349):        <!--<xs:group ref="block"/>-->
XSD\xhtml1-strict.xsd(1351):        <!--<xs:group ref="inline"/>-->
XSD\xhtml1-strict.xsd(1352):        <!--<xs:group ref="misc"/>-->
XSD\xhtml1-strict.xsd(1450):          <!--<xs:group ref="block"/>-->
XSD\xhtml1-strict.xsd(1452):          <!--<xs:group ref="misc"/>-->
XSD\xhtml1-strict.xsd(1718):          <!--<xs:group ref="block"/>-->
XSD\xhtml1-strict.xsd(1720):          <!--<xs:group ref="inline"/>-->
XSD\xhtml1-strict.xsd(1721):          <!--<xs:group ref="misc"/>-->

I am also sharing my notes so far regarding manual edits required, to fix issues in the classes generated.

Generate entities with Xsd2Code add-in from www.codeplex.com\Xsd2Code

Use fhir-atom-single.xsd as the source XSD
Use Parms:
    Serilization.GenerateXMLAttributes = true
    Code.Namespace = Hl7.Fhir.Validation.SchematronOutput
    Collection.CollectionObjectType=Array

!!! Do not open Schema in Designer, or classes will change.

Manual updates:

    public partial class boolean : Element
    ...
        [System.Xml.Serialization.XmlAttributeAttribute("value")]
        public bool Value
        {


    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = false, Namespace = "http://www.w3.org/1999/xhtml")]
    public partial class div : Flow


    Refactor:
    public partial class FeedType
    to
    public partial class feed
jlo-gmail
  • 4,453
  • 3
  • 37
  • 64
0

Thanks to Petru, the command is: xsd.exe fhir-atom-single.xsd tombstone.xsd fhir-single.xsd opensearch.xsd opensearchscore.xsd xmldsig-core-schema.xsd xhtml1-strict.xsd xml.xsd /c

and the classes do get created after the circular references are commented out of xhtml1-strict.xsd

However, as Ewout points out this is not a complete fix, because the schemas themselves are designed to be unfriendly to POCO classes.

In the patient class this element:

  <xs:choice minOccurs="0" maxOccurs="1" >
    <xs:annotation>
      <xs:documentation>Indicates if the individual is deceased or not.</xs:documentation>
    </xs:annotation>
    <xs:element name="deceasedBoolean" type="boolean"/>
    <xs:element name="deceasedDateTime" type="dateTime"/>
  </xs:choice>

Yields:

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("deceasedBoolean", typeof(boolean))]
[System.Xml.Serialization.XmlElementAttribute("deceasedDateTime", typeof(dateTime))]
public Element Item {
    get {
        return this.itemField;
    }
    set {
        this.itemField = value;
    }
}

I have reported these findings on the FHIR comments and hope they will be addressed. In the meantime I can proceed with my original intention. A SOAP implementation of an API using these definitions.

jlo-gmail
  • 4,453
  • 3
  • 37
  • 64
  • Hi user824791....is there anything we could do to make the generated classes in the distribution better fit your needs? E.g. should I generate Xml.Serialization attributes as well? What could make the schema's less unfriendly? – Ewout Kramer Feb 19 '14 at 22:49
  • Anything you can do to make it possible to create complete classes using xsd.exe would seem to be the first priority. Next the classes need to be completely serializable/deserializable. (so far patient.active.value fails to serialize, while patient.active.id does. I have no idea why.) This whole process should be completely automatable. Unittests would be able to verify issues like patient.active.value before a release. Next it seems to me the API should be limited to helping build and validating an object. – jlo-gmail Feb 21 '14 at 01:51
  • Just my opinion, from a design POV, the entities should be simple. Ideally, they should have no methods related to serilization, or assisting with handling the structure (ie AndFamily on HumanName and Validate ) . I have made this mistake personally. entitles should be simple POCOs that way they serialize without any custom code - xml, soa, or json, etc. The methods like AndFamily and Validate make sense in toolkit classes that are shared. These are required due to the complexity of the model. – jlo-gmail Feb 21 '14 at 22:08
  • Rereading this thread...the generated classes are pretty clean. The Serialization methods are separated out into a FhirSerializer and FhirParser class. The helper methods like AndFamily aren't actually on HumanName, but are added as Extension methods that are part of -indeed- a separate toolkit class. – Ewout Kramer Apr 15 '14 at 14:55