Linq to XML is a part of Linq I never did like very much. Everything hangs together with loosely typed strings. For example:
var query = from xElem in doc.Descendants("Patient")
select new Patient { EMail = xElem.Attribute("EMail").Value,
FirstName = xElem.Element("FirstName").Value,
LastName = xElem.Element("LastName").Value, };
Meet Linq to XSD. Here you use a XML schema to make your queries strongly typed.
Linq to XSD is still in beta, you can download it at codeplex.
There is not yet a clean and mean installer for it. To install, follow the steps posted here.
Just change one thing in the installation procedure, in step 9, change $(SolutionDir) into the folder where you installed the binaries.
In my case:
<LinqToXsdBinDir Condition="'$(LinqToXsdBinDir)' == ''">c:\LINQTOXSDBIN\</LinqToXsdBinDir>
Now, just create an XML file and make a schema for it by using the Visual Studio “Create xml schema” button and
tweak it a bit. If you, like me do not know the syntax by heart, look here.
Once you have your schema, you can use an existing one too of course, place it inside the project mentioned in
the installation guide.
Be sure to include a “targetNamespace” in your schema:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.oosterkamp.nl/conversionconfiguration">
Select the xsd file in the project en go to the properties pane. Set the build action to “LinqtoXsdSchema”.
Now, build your project.
There is a new namespace available now. It has the name of the uri specified as targetNamespace,
but without the http:// prefix and the slashes are dots.
In my case the namespace is www.oosterkamp.nl.conversionconfiguration .
Ok, maybe this is not the nices feature of Linq to XSD.
Inside the namespace is a class. It’s name is the name of your root node. It has a static method called Load, that get’s you to load a xml file.
The file has to validate with the schema.
using www.oosterkamp.nl.conversionconfiguration;
..
ConversionConfiguration xmlData = ConversionConfiguration.Load("ConversionConfiguration.xml");
Now the Linq party can really begin, because everything is strongly typed now. And if you’re used to Linq to SQL or Linq to Entities,
this works exactly the same, even updating and inserting data!
var repositories = from repository in xmlData.Repositories.Repository
select repository.name;
Here’s my full xsd:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.oosterkamp.nl/conversionconfiguration">
<xs:element name="ConversionConfiguration">
<xs:complexType>
<xs:sequence>
<xs:element name="Repositories">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Repository">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="invariantProviderName" type="xs:string" use="required" />
<xs:attribute name="connectionString" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Conversions">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Conversion">
<xs:complexType>
<xs:sequence>
<xs:element name="LastTimeStampProcessed" type="xs:dateTime" />
</xs:sequence>
<xs:attribute name="repositoryAName" type="xs:string" use="required" />
<xs:attribute name="respositoryBName" type="xs:string" use="required" />
<xs:attribute name="tableNameFromRepositoryA" type="xs:string" use="required" />
<xs:attribute name="tableNameFromRepositoryB" type="xs:string" use="required" />
<xs:attribute name="fieldNameFromRepositoryA" type="xs:string" use="required" />
<xs:attribute name="fieldNameFromRepositoryB" type="xs:string" use="required" />
<xs:attribute name="direction" use="required">
<xs:simpleType>
<xs:restriction base ="xs:string">
<xs:enumeration value ="fromAtoB"/>
<xs:enumeration value ="bidirectional"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Here’s my full xml file:
<?xml version="1.0" encoding="utf-8" ?>
<ConversionConfiguration>
<Repositories>
<Repository name="Access" invariantProviderName="dfdf" connectionString="sdfsdf"></Repository>
<Repository name="SQL" invariantProviderName="dfdf" connectionString="sdfsdf"></Repository>
</Repositories>
<Conversions>
<Conversion repositoryAName="Access" respositoryBName="SQL" tableNameFromRepositoryA="Customers" tableNameFromRepositoryB="Customer" fieldNameFromRepositoryA="Address"
fieldNameFromRepositoryB="Adres" direction="fromAtoB">
<LastTimeStampProcessed>"2010/01/01"</LastTimeStampProcessed>
</Conversion>
<Conversion repositoryAName="Access" respositoryBName="SQL" tableNameFromRepositoryA="Orders" tableNameFromRepositoryB="order" fieldNameFromRepositoryA="naampje"
fieldNameFromRepositoryB="naam" direction="bidirectional">
<LastTimeStampProcessed>"2010/01/01"</LastTimeStampProcessed>
</Conversion>
</Conversions>
</ConversionConfiguration>