Generate Nested Types instead of Global Types with xsd.exe - xsd

Using xsd.exe in a C# class, is there a way to produce a xsd file with Nested Type, instead of Global Types?
I want to use this xsd file, with SSIS - Sql Server Integration Services, and look SSIS is not reading my xsd very well.
I want to generate the xsd like this, with Nested Types :
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:mstns="http://tempuri.org/XMLSchema.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Country">
<xs:complexType>
<xs:sequence>
<xs:element name="City">
<xs:complexType>
<xs:sequence>
<xs:element name="CityName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CoutryName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
but xsd.exe produce this , with Global Types, and SSIS don't read it. I need to change this xsd manually to be like above.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:mstns="http://tempuri.org/XMLSchema.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Country">
<xs:complexType>
<xs:sequence>
<xs:element name="City" type="City">
</xs:element>
<xs:element name="CoutryName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="City">
<xs:sequence>
<xs:element name="CityName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Any suggestion? Or other tool that I can use.
Thanks a lot.

I'll further assume that not "very well" means you're not seeing CountryName in your XML Source output.
The documentation on MSDN is a good reading, although in my opinion it fails to describe why you would encounter the behavior you see.
I believe that it has to do with the way XML Source outputs are being determined. SSIS infers a data set from the XML structure; the top level entity, that corresponds to the root element, is not mapped to an output, so all the attributes associated with it, in your case CountryName, will not show up.
The easiest way to prove it, is to add another root element that wraps your Country (equivalent to having a dummy "root" class that has a Country-type property).
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="Country"/>
</xs:sequence>
</xs:complexType>
</xs:element>
If you add the above schema fragment to your schema, you should get your expected results. At the beginning I thought that it has to do with the issue described here; while you can still use the tool to visualize the data set as described by the MSDN link above, in your case, the authoring style you suggested (basically a russian-doll) can't change the outcome.

Related

Create an XSD that supports something like web.config transforms or multi-tenant/configuration xml files

I have an Xml file like this:
<Configuration xmlns="http://schemas.benefittech.com/evolution/site">
<SiteSettings>
<ProfileGroup>TBOLoanPmtElection</ProfileGroup>
<AWSGroup>TBOLoanPmtElection_Admin</AWSGroup>
</SiteSettings>
</Configuration>
And I have an XSD file like this:
<?xml version="1.0" encoding="us-ascii" ?>
<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified" version="5.0"
xmlns="http://schemas.benefittech.com/evolution/site" targetNamespace="http://schemas.benefittech.com/evolution/site"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vs="http://schemas.benefittech.com/Visual-Studio-Intellisense" vs:friendlyname="Evolution Site Configuration">
<xs:element name="Configuration">
<xs:complexType>
<xs:all>
<xs:element name="SiteSettings" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="AWSGroup" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ProfileGroup" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="LogActivityGroup" type="xs:string" minOccurs="0" maxOccurs="1"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
I want to enable my Xml to look something like the following to allow for 'environment overrides' (the E attribute on the env:* element):
<Configuration xmlns="http://schemas.benefittech.com/evolution/site" xmlns:env="http://schemas.benefittech.com/evolution/siteenvironment">
<SiteSettings>
<ProfileGroup>TBOLoanPmtElection</ProfileGroup>
<AWSGroup>TBOLoanPmtElection_Admin</AWSGroup>
<env:AWSGroup E="SecondEnvironment">TBOLoanPmtElection2_Admin</env:AWSGroup>
</SiteSettings>
</Configuration>
Is there a way to modify the XSD so that given EVERY element in my configuration, I want to optionally have a env:* version of it. Do I have to make a new schema file like below that is basically a duplicate of original except for the target namespace?
<?xml version="1.0" encoding="us-ascii" ?>
<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified" version="5.0"
xmlns="http://schemas.benefittech.com/evolution/siteenvironment" targetNamespace="http://schemas.benefittech.com/evolution/siteenvironment"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vs="http://schemas.benefittech.com/Visual-Studio-Intellisense" vs:friendlyname="Evolution Site Configuration">
<xs:element name="Configuration">
<xs:complexType>
<xs:all>
<xs:element name="SiteSettings" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="AWSGroup" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="E" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="ProfileGroup" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="E" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="LogActivityGroup" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="E" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
Is there a way to modify the XSD so that given EVERY element in my configuration, I want to optionally have a env:* version of it.
No, there is no elegant way to add, after each element, an optional element having the same name but a different namespace. You would need to add each such env:* element individually.
Do I have to make a new schema file like below that is basically a duplicate of original except for the target namespace?
Yes, but only if you stick to this plan of using a different namespace for the 'extension' elements. In your reply to my comment you said
I thought I'd need separate namespaces. I didn't want to change code everywhere that selects elements. For example, SiteConfig.Elements( "SiteSettings" ).Elements( "AWSGroup" ).FirstOrDefault(); Would continue to work without picking up the env:* elements. Then during the publish process, I would swap out the env:* properties everywhere and code would just work. What's your suggestion?
I've hardly written a line of C#, but according to https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.firstordefault?view=netcore-3.1 the FirstOrDefault() method returns the first element in the sequence or a default. So I think there is a much simpler approach that will not break the existing code...
On each element that needs to have option extension element(s):
Set maxOccurs="unbounded" (or "2", if you only want to allow one extension element)
Add the attribute "E" and make it optional (so that existing documents which omit it on the first occurrence are still valid).
The name "E" for the attribute is not ideal - I would pick something more descriptive if possible.

Schema with elements, attributes, and text

I am having trouble getting this XML file to validate against my schema, which doesn't have syntax errors according to my XML editor. I am trying to make course an complexType element, but it keeps telling me I can't. The XML is correct, it is definitely something with my schema, I just can't figure it out.
Here is the XML:
<?xml version="1.0" encoding="utf-8"?>
<courses xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="course_offerings.xsd">
<course id="WEB225">
<name>Web Development II</name>
<offered>Spring</offered>
<pre_reqs>WEB125</pre_reqs>
</course>
<course id="WEB125">
<name>Web Development I</name>
<offered>Fall</offered>
</course>
<course id="WEB325">
<name>Client-Side Scripting</name>
<offered>Spring</offered>
<offered>Fall</offered>
<pre_reqs>WEB225</pre_reqs>
</course>
</courses>
And here is my schema:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="courses">
<xs:complexType>
<xs:sequence>
<xs:element name="course" type="xs:string"/>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="offered" type="xs:string"/>
<xs:element name="pre_reqs" type="xs:string"/>
</xs:sequence>
</xs:sequence>
<xs:attribute name="id" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:schema>
Since you haven't mentioned what error you are getting, I'm providing what I can observe..
In your XML you have included this statement: xsi:noNamespaceSchemaLocation="course_offerings.xsd" This means it is your default XML schema. You need to verify the name of schema and make sure it is present in default path.. (same as that of XML file). Otherwise you may end up seeing an error unable to locate schema
course_offerings.xsd
You have declared <xs:element name="course" type="xs:string"/> as string .. that should not be the case.. In your XML it's a complexType, ie, an element having child elements inturn..
All these elements name, offered, pre_reqs should come under this complexType
Attribute should be within the scope of this complexType..
Otherwise you would face not just one but multiple errors since the definition of element course is invalid
Refer the sample XSD below:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="courses">
<xs:complexType>
<xs:sequence>
<xs:element name="course">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="offered" type="xs:string"/>
<xs:element name="pre_reqs" type="xs:string"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The above mentioned style is hierarchical, there is an alternative method to write a schema file.. If you understand the current consequences and if you wish to know further then I will let you know..
For now this much explanation should be good..

XSD my data type

I would like to ask about .XSD document. I cannot find anything about creating my own type, for example:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Client">
<xs:sequence>
<xs:element name="FirstName" type="string"/>
<xs:element name="SecondName" type="string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Contact">
<xs:sequence>
<xs:element name="contacts" type="Client" minOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xsd:schema>
And I would like to know is that right way to define my own type contact?
A few points that were not quite right.
The xsd: namespace alias on the closing schema tag should be just xs:
The primitive string types need there types qualifying, ie xs:string.
From a style point of view ComplexTypes should end Type.
If you want to use the schema (presumably via the Contact) then you need to declare a root element.
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid XML Studio 2012 Developer Edition (Trial) 10.0.1.3941 (http://www.liquid-technologies.com)-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ClientType">
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="SecondName" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="ContactType">
<xs:sequence>
<xs:element name="contacts" type="ClientType" minOccurs="1" />
</xs:sequence>
</xs:complexType>
<xs:element name="Client" type="ClientType" />
</xs:schema>
Basically XML Schemas are complex things to write without a tool. I'd seriously look into getting a good schema designer, I'd recommend Liquid XML Studio.

Why won't XML Schema allow me to define a one-to-many key? And how do I do so?

I'm falling over on a frustrating, arbitrary restriction in XML Schema. For some reason, it insists that PK-FK relationships have to be one-to-one. Why?
For example, given the schema:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="FutureSchema"
targetNamespace="http://tempuri.org/FutureSchema.xsd"
elementFormDefault="unqualified"
xmlns="http://tempuri.org/FutureSchena.xsd"
xmlns:mstns="http://tempuri.org/FutureSchema.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="FUTUREFILE">
<xs:complexType>
<xs:sequence>
<xs:element name="Configuration">
<xs:complexType>
<xs:sequence>
<xs:element name="Experiments">
<xs:complexType>
<xs:sequence>
<xs:element name="Experiment">
<xs:complexType>
<xs:attribute name="ID" type="xs:integer"/>
<xs:attribute name="Profile" type="xs:integer"/>
</xs:complexType>
<xs:keyref name="dummy" refer="LP">
<xs:selector xpath="Experiment"/>
<xs:field xpath="#Profile"/>
</xs:keyref>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:key name="LP">
<xs:selector xpath="*/Configuration/Profiles/Profile"/>
<xs:field xpath="#ID"/>
</xs:key>
</xs:element>
<xs:element name="Profiles">
<xs:complexType>
<xs:sequence>
<xs:element name="Profile">
<xs:complexType>
<xs:attribute name="ID" type="xs:integer"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
And an example instance:
<?xml version="1.0" encoding="utf-8" ?>
<b:FUTUREFILE xmlns:b="http://tempuri.org/FutureSchena.xsd">
<Configuration>
<Experiments>
<Experiment ID="1" Profile="1"/>
<Experiment ID="2" Profile="1"/>
</Experiments>
<Profiles>
<Profile ID="1"/>
</Profiles>
</Configuration>
</b:FUTUREFILE>
Document validation throws an error if I define <Experiment ID="1" FK="1"/><Experiment ID="2" FK="1"/>, for example; i.e. more than one Experiment may not reference the same Profile. But why else would I want to use a key relationship? What use is a key relationship at all if I can't do something so fundamental?
OK, if and won't let me do this, how should I?
edit #1: As requested, I've padded out my code sample to include the full schema and a basic instance.
edit #2: Interesting. SharpDevelop's XML editor (as opposed to Visual Studio's) doesn't seem to object. It doesn't object to the foreign key value referring to a nonexistent primary key either (which IMO it should) but it's a start.
What wasn't clear ?... My english, it's all :-)
Some remarqs, I'm not sure it's solution :
In exemple instance, it's best to use xmlns:b="http://tempuri.org/FutureSchema.xsd">, and not xmlns:b="http://tempuri.org/FutureSchena.xsd"> (n -> m).
Also it's best to put b: in front of all elements names.
According to your schema, you can't have two Experiment in Experiments, only one.
On xsd, put <xs:keyref name="dummy" refer="mstns:LP">, that works best for me ; it's because xpath expression doesnt't understand default namespace, see Correct way to use key in xsd.

What is wrong with extending an XML Schema type using xs:all?

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="http://tempuri.org/ServiceDescription.xsd" xmlns:mstns="http://tempuri.org/ServiceDescription.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://tempuri.org/ServiceDescription.xsd" elementFormDefault="qualified" id="ServiceDescription">
<xs:element name="Template">
<xs:complexType>
<xs:complexContent>
<xs:extension base="ServiceType">
<xs:all>
<xs:element name="TemplateCode" type="xs:string"/>
</xs:all>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:complexType name="ServiceType">
<xs:all>
<xs:element name="ServiceCode" type="xs:string"/>
</xs:all>
</xs:complexType>
</xs:schema>
When I try to save this in XMLSpy it tells me
An 'all' model group is neither allowed in complex type definition 'mstns:ServiceType' nor in its extension '{anonymous}'.
Clicking Details gives a link to a paragraph in XML Schema specification which I do not understand.
Added: Ah, yes, forgot to mention - the line of error is this one:
<xs:element name="TemplateCode" type="xs:string"/>
The problem is you can't have all if you're extending another type. As far as XML knows the parent type might have a sequence model and since XML forbids putting an all group inside of a sequence group (since that would destroy the sequence group's ordering) then XML also forbids putting an all group in an extension of a complex type. You could use sequence instead of all for both though and you'd be fine.

Resources