I'm working on some code generation for an existing project and I want to start from a xsd. So I can use tools as Xsd2Code / xsd.exe to generate the code and also the use the xsd to validate the xml. That part works without any problems.
I also want to translate some of the restrictions to DataAnnotations (enrich Xsd2Code).
For example xs:minInclusive / xs:maxInclusive I can translate to a RangeAttribute.
But what to do with custom validation attributes that we created? Can I add custom facets / restrictions? And how? Or is there another solution / best practice.
I would like to collect everything in a single (xsd) file so that one file contains the structure of the class (model) including the validation (attributes) that has to be added.
<xs:element name="CertainValue">
<xs:simpleType>
<xs:restriction base="xs:double">
<xs:minInclusive value="1" />
<xs:maxInclusive value="100" />
<xs_custom:customRule attribute="value" />
</xs:restriction>
</xs:simpleType>
</xs:element>
XML schema is itself schema constrained, so you can't add an arbitrary (in its eyes) element. There is a facility for adding anything you like, xs:annotation/xs:appinfo, that's available for addition to most nodes. Perhaps try something like this:
<xs:element name="CertainValue">
<xs:simpleType>
<xs:restriction base="xs:double">
<xs:annotation>
<xs:appinfo>
<xs_custom:customRule attribute="value" />
</xs:appinfo>
</xs:annotation>
<xs:minInclusive value="1" />
<xs:maxInclusive value="100" />
</xs:restriction>
</xs:simpleType>
It depends on where Xsd2Code is looking for the stuff, but if they expect XSDs passed in to validate, appinfo is probably their only choice. Just which element to add the appinfo on it also of question.
Related
I am an experienced programmer but just recently took on a job maintaining an app that uses xml schema. They want to add some validation on an item that accepts Longitude. They want to continue to accept a blank and also 0, 0.0000000, or if another value is entered they want to make sure that at the least it is in the United States. (i.e. between -125 and -67)
The current xml schema simply allows any value.
<xs:element name="Location">
<xs:complexType>
<xs:sequence>
<xs:element name="LocLongitude"/>
</xs:sequence>
</xs:complexType>
</xs:element>
There are multiple venders sending this info in. Here is an example of what they may send:
<Location>
<LocLongitude xsi:type="xsd:string"></LocLongitude>
</Location>
Now looking at what the users want I found that I can use a union to encapsulate multiple checks. This is what I am using now.
<xs:element name="Location">
<xs:complexType>
<xs:sequence>
<xs:element name="LocLongitude" nillable="true">
<xs:simpleType>
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value=""/>
<xs:enumeration value="0"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:double">
<xs:minInclusive value="0.00000000"/>
<xs:maxInclusive value="0.00000000"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:double">
<xs:minInclusive value="-125"/>
<xs:maxInclusive value="-67"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
It validates correctly if I use:
<Location>
<LocLongitude />
</Location>
Now if I use what the current vendors are using (see below):
<Location>
<LocLongitude xsi:type="xsd:string"></LocLongitude>
</Location>
We get an error:
THE XSI:TYPE ATTRIBUTE VALUE '' IS NOT VALID FOR THE ELEMENT 'LOCLONGITUDE', EITHER BECAUSE IT IS NOT A TYPE VALIDLY DERIVED FROM THE TYPE IN THE SCHEMA, OR BECAUSE IT HAS XSI:TYPE DERIVATION BLOCKED.
My question is, can I get this to work while still allowing the vendors to include xsi:type="xsd:string"?
No, the type chosen for xs:type must be validly derived from the type provided by the associated element. You cannot on the one hand define a type that restricts the value space and on the other hand supports a broader xs:type declaration.
See also: How to restrict the value of an XML element using xsi:type in XSD?
I have written an application which receives many variation of XML requests. In our business we have to validate XMLs against XSD at the beginning of any request.
The problem:
As I said above I have to validate them at the beginning and those XMLs have almost the same schema and I need to write a general XSD for them.
I have provided some prototype XML for my question:
XML1:
<_9D94DEB4-7C2D-45A5-A4FB-89FB1CF20672>
<Param1>value</Param1>
<Type>Category</Type>
</_9D94DEB4-7C2D-45A5-A4FB-89FB1CF20672>
XML2: Almost the same schema but root element name is different and it has an extra child element.
<_7603DCD1-F270-43EA-86E3-0FB3161478F6>
<Param1>value</Param1>
<Type>Page</Type>
<SearchText>Sample</SearchText>
</_7603DCD1-F270-43EA-86E3-0FB3161478F6>
As you can see the root element names are different but their schema is almost the same, How could I write a general XSD for them?
Thanks in advance.
The only thing these two XML instances have in common is that both have a Type element whose value is a string. Calling that "almost the same schema" seems rather an exageration. But perhaps there is more commonality than you have shown us?
In principle XSD allows you to validate the instance against a global type in your schema, irrespective of the element name. Whether your particular schema processor provides an API to do that is another question.
Your schema could then simply define the top-level type:
<xs:complexType name="myTopLevelType">
<xs:sequence>
<xs:element name="Param1" type="xs:string"/>
<xs:element name="Type" type="xs:string"/>
etc
</xs:sequence>
</xs:complexType>
If you choose Saxon as your schema validator then you can invoke "validation-by-type" from the Java API but not from the command line. In fact, probably the easiest way to do it is to invoke the validation from XSLT:
<xsl:import-schema schemaLocation="mySchema.xsd"/>
then:
<xsl:copy-of select="doc('instance.xml')/*" type="myTopLevelType"/>
All you need to do is write each of roots as direct children of your schema element and define types in your XSD.
For example:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="_9D94DEB4-7C2D-45A5-A4FB-89FB1CF20672">
...
<xs:complexType>
<xs:attribute name="Param2" type="Param2" use="required">
</xs:attribute>
<xs:attribute name="Type" type="Type" use="required">
</xs:attribute>
<xs:attribute name="SearchText" type="SearchText" use="required">
</xs:attribute>
</xs:complexType>
...
</xs:element>
<xs:element name="_7603DCD1-F270-43EA-86E3-0FB3161478F6">
...
<xs:complexType>
<xs:attribute name="Param1" type="Param1" use="required">
</xs:attribute>
<xs:attribute name="Type" type="Type" use="required">
</xs:attribute>
</xs:complexType>
...
</xs:element>
</xs:schema>
<!-- Your defenition and restriction of types-->
<xs:simpleType name="Param1">
<xs:restriction base="xs:string">
</xs:simpleType>
<xs:simpleType name="Param2">
<xs:restriction base="xs:string">
</xs:simpleType>
<xs:simpleType name="Type">
<xs:restriction base="xs:string">
</xs:simpleType>
<xs:simpleType name="SearchText">
<xs:restriction base="xs:string">
</xs:simpleType>
I am using xsd to generate the object available in the OperationContract. The address, city, state and zip elements of the XSD are common
<xs:element name="Address" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="50"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
and used throughout the XML.
<xs:element ref="Address" />
When I compile the schema the classes generate correctly using the common elements.
When I run the service the OperationContext contains the expected request from the client:
<NameLast>Last</NameLast>
<NameFirst>First</NameFirst>
<Address xmlns="http://tempuri.org/">123 2nd St</Address>
<City xmlns="http://tempuri.org/">Somewhere</City>
However the common elements have the xmlns attribute (shown above) and in the received object all common elements contain null values.
My reputation is not high enough to show screenshot, but all data NOT in common elements are passed correct. Such as NameLast = "Last", Address = Null.
I am new to using Schemas and would appreciate any direction. Thanks.
I believe what you want is this, placed before your closing </xs:schema> tag:
<xs:simpleType name="AddressType">
<xs:restriction base="xs:string">
<xs:maxLength value="50"/>
</xs:restriction>
</xs:simpleType>
and used throughout the schema:
<xs:element name="Address" type="AddressType" />
I have been using biztalk for a few months now, and have learned the in's and out of basic and intermediate level Project creation. Today however I have noticed something at the Beginner level concepts that I must have missed (schema creation). In a project I created using a Schema named "NewSchema" I created a screen record with id and parentid attributes, msg element, and four records named A-D, which are meant to be elements, but with an attribute named ChildID.
I had originally done this project in a C# program I had written to better teach myself how to iterate through XML elements. Now I have adapted the program to biztalk where I noticed elements cannot have "attributes"? To work around this A-D would have to be records with attributes, then I'd have to make a child element of the same name of the record for each A-D record.
Are elements with attributes possible in biztalk? I'm surprised I have never come across this before.
It'll work if I do this:
<ns0:Root xmlns:ns0="http://WcfServerProject.NewSchema">
<Screen ID="ID_0" ParentID="ParentID_1">
<MSG>MSG_0</MSG>
<A ChildID="ChildID_0">
**<A>Hello World</A>**
</A>
<B ChildID="ChildID_0" />
<C ChildID="ChildID_0" />
<D ChildID="ChildID_0" />
</Screen>
</ns0:Root>
But can I create my project this way in biztalk?:
<ns0:Root xmlns:ns0="http://WcfServerProject.NewSchema">
<Screen ID="ID_0" ParentID="ParentID_1">
<MSG>MSG_0</MSG>
**<A ChildID="ChildID_0">
Hello World
</A>**
<B ChildID="ChildID_0" />
<C ChildID="ChildID_0" />
<D ChildID="ChildID_0" />
</Screen>
</ns0:Root>
Try using the generate xsd from well-formed xml function, you will get xsd kind of like this:
<xs:element name="A">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="ChildID" type="xs:string" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
Ok My Elements can have attributes and data now after switching "Mixed" to "True".
I am using VS2010 and using the "add service reference" feature, to generate client classes from my WSDL. I am having a problem with one of my elements, which is defined in the WSDL as follows:
<xs:simpleType name="NumberType">
<xs:restriction base="xs:string">
<xs:enumeration value="ONE" />
<xs:enumeration value="TWO" />
<xs:enumeration value="THREE" />
</xs:restriction>
</xs:simpleType>
This type is used in one of my elements like this:
<xs:element name="NumberTypes">
<xs:simpleType>
<xs:list itemType="tns:NumberType" />
</xs:simpleType>
</xs:element>
The problem is that VS is converting this particular element to a string type, when it should be an enumeration. so it converts it to a string NumberTypes which has a get method returning numberTypesField also of type string.
I think the problem is related to the fact that my schema NumberTypes element uses the xs:list, with 'itemType' attribute. if I change this to xs:element with type="tns:NumberType" attribute instead then the enumeration is generated as it should be.
So how can I make the enumeration work with xs:list? Why is it not converting correctly in the first place?
Thanks for any help.
I haven't had much luck getting xs:list to serialize properly. Instead, I just allow for multiple instances of the same node, and .NET knows how to put it into a "list" or "array" properly.
<xs:element minOccurs="0" maxOccurs="unbounded" name="NumberTypes">
...
</xs:element>