Low Level Biztalk schema creation - c#

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".

Related

How to add element conditionally to XSD based on the value of another element

I have a scenario, where the first element (Mode) can have a value of either Add/Edit/Delete.
Now, I need to have another element (ID) based on the value of the first element.
if the first element value is Add then the XML validation should fail if the second element exists.
if the first element value is either Edit/Delete then the second element is required in the XML for the validation to pass.
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="mode">
<xs:restriction base="xs:string">
<xs:enumeration value="Add"/>
<xs:enumeration value="Edit"/>
<xs:enumeration value="Delete"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="Request">
<xs:complexType>
<xs:sequence>
<xs:element name="Mode" type="mode" minOccurs="1"></xs:element>
<xs:element name="ID" type="xs:string" minOccurs="0"></xs:element>
</xs:sequence>
<xs:assert test="not(Mode != 'Add') or ID"/>
</xs:complexType>
</xs:element>
I tried adding xs:assert to add conditional validation but I'm getting the below error
The 'http://www.w3.org/2001/XMLSchema:assert' element is not supported in this context.
xs:assert is only available in XSD 1.1, which .NET does not support. For XSD 1.1, use Saxon instead.
XSD 1.0 solution
Content model constraints in XSD 1.0 are based on component names. You'll have to redesign your XML to represent Add vs Edit vs Delete as elements rather than as attribute values to express ID's different occurrence constraints depending on request type.
Rather than
<Request>
<Mode>Add</Mode>
</Request>
<Request>
<Mode>Edit</Mode>
<ID>1</ID>
</Request>
<Request>
<Mode>Del</Mode>
<ID>2</ID>
</Request>
use
<Add></Add>
<Edit>
<ID>1</ID>
</Edit>
<Del>
<ID>2</ID>
</Del>
This design can easily be accommodated in XSD 1.0.

Error parsing an XSD schema - Undefined complexType

I'm currently trying to add this XSD as a Service Reference to My ASP .Net MVC 4 project (http://voip.letscall.pt/PortalWebAPI/metadata?xsd=1). The problem is that whether I'm doing something wrong or the file has some kind of problem.
When I try to use the XSD.exe to parse the XSD, it gives me this error
Undefined complexType
'http://schemas.datacontract.org/2004/07/VS.PortalWebAPI:SupportTypes:Paging'
is used as a base for complex type extension.
The Paging SupportType is used on complexTypes, such as
<xs:complexType name="GetPbxCompanyContacts">
<xs:complexContent mixed="false">
<xs:extension xmlns:q13="http://schemas.datacontract.org/2004/07/VS.PortalWebAPI.API.SupportTypes" base="q13:Paging">
<xs:sequence>
<xs:element minOccurs="0" name="BranchId" type="xs:int" />
<xs:element minOccurs="0" name="Login" nillable="true" type="xs:string" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="GetPbxCompanyContacts" nillable="true" type="tns:GetPbxCompanyContacts" />
The PortalWebAPI has 5 files:
XSDS
Service Types (voip.letscall.pt/PortalWebAPI/metadata?xsd=1)
Wcf Data Types (voip.letscall.pt/PortalWebAPI/metadata?xsd=0)
Wcf Collection Types (voip.letscall.pt/PortalWebAPI/metadata?xsd=2)
WSDLS
soap11 (voip.letscall.pt/PortalWebAPI/soap11)
soap12 (voip.letscall.pt/PortalWebAPI/soap12)
However, I've still not managed to find how to use it. Do I need only one, or do I need to import all?
I've also tried to add it straight to the project, through References -> Add Service Reference, only one or all of them, but no luck.
There should be a complexType named Paging in the XML schema document which has the target namespace mapped to the q13 prefix. Look for the document with:
targetNamespace="http://schemas.datacontract.org/2004/07/VS.PortalWebAPI.API.SupportTypes"
It should contain the Paging type.
You also should have an xs:import statement:
<xs:import namespace="http://schemas.datacontract.org/2004/07/VS.PortalWebAPI.API.SupportTypes"
schemaLocation="/path/to/your-schema.xsd"/>
If the Paging type is not declared in that namespace, or if you don't import the schema, it will not be found when you try to use it in your extension.

c# read DataSet Child tables

<products>
<product id="1">
<photos>
<photo addr="1.jpg" />
</photos>
<parameters>
<parameter name="name" />
</parameters>
</product>
</products>
Hello, I have this xml, I want to get values, like photo addr or parameter name I can't.
in DataGrid I am getting like new table. How to Read this parameters by product id?
foreach (DataTable t in dataSet.Tables)
{
Console.WriteLine(t);
}
I am getting: product, photos, photo, parameters, parameter.
Sorry for my English
OK, you need to use schema inferencing to generate an XSD file, then run xsd.exe to generate the DataSet that you're looking for.
To begin with, the XML you've provided won't work off the bat, because you don't have a root node. I'm taking a wild guess here, but if <products> is the root node, we could reformat your XML to look like this:
<products>
<product id="1">
<photos>
<photo addr="1.jpg" />
</photos>
<parameters>
<parameter name="name1" />
</parameters>
</product>
<product id="2">
<photos>
<photo addr="2.jpg" />
</photos>
<parameters>
<parameter name="name2" />
</parameters>
</product>
</products>
We could then take this XML and infer the XSD from it via the XmlSchemaInference class. When I inferred the schema from the XML above, I got this:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="products">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="product">
<xs:complexType>
<xs:sequence>
<xs:element name="photos">
<xs:complexType>
<xs:sequence>
<xs:element name="photo">
<xs:complexType>
<xs:attribute name="addr" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="parameters">
<xs:complexType>
<xs:sequence>
<xs:element name="parameter">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I then ran xsd.exe with the /dataset option, which gave me a fully functional DataSet representing the original XML. Populating the dataset and the using the DataSet.GetXml() returns the expected XML result.
Final note: I'm not advocating the use of DataSets over domain objects, etc etc. I just wanted to show you what would be the steps for accomplishing your stated objective.
By default DataSet assumes a schema based on elements, not attributes. You'd need to build an xsd for your data to get DataSet to read that XML correctly.
Due to the way this XML is constructed there's no easy way to read this into a DataSet directly. You'd have to use xsd.exe to generate an xsd file and then hand edit it with appropriate attributes from the msdata namespace. It's a quite painful process.
You coud transform the document to a form which would probably parse correctly into DataSet either by rewriting the XML using LINQ or applying an XslCompiledTransform:
<products>
<product id="1">
<photo addr="1.jpg" />
<parameter name="name" />
</product>
</products>
You could also consider using LINQ to XML on it instead of trying to use a DataSet:
var productsInfo = from product in productsElement.Descendants("product")
from photo in product.Descendants("photo")
from parameter in product.Descendants("parameter")
let id = product.Attribute("id")
let addr = photo.Attribute("addr")
let name = parameter.Attribute("name")
select new { ID = id.Value, Addr = addr.Value, Name = name.Value};
If you're developing a new XML layout rather than working with an existing one, you can create the DataSet first using the designer. Populate it with some dummy data, then you can use WriteXml to get the xsd schema and sample data. To preserve relationshps in the XML ouput be sure to set the Nested property on your Relations to be true (See Nesting DataRelations (ADO.NET)).

How can I make my WCF message contract show up in the imported schema?

A client provided us with schemas and a wsdl for a service they would like developed. When I jumped on the project, there was already a service implementation in place. When I pull up the svc file in IE, it shows the normal svcutil command etc.. When I drill down and I look at the schemas being imported by the wsdl we're using, I notice that the MessageContracts are not showing up in the schema. What can I do to make the MessageContracts show up so the schemas will be idetentical?
For instance, the customer gave us this,
<xs:schema elementFormDefault="qualified" targetNamespace="http://ws.tcore.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://ws.tcore.com">
<xs:import schemaLocation="ATISDataContracts.xsd" namespace="http://schemas.datacontract.org/2004/07/tcore.ATISDataContracts" />
<xs:import schemaLocation="Serialization.xsd" namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
<xs:element name="ASICDetectorInventoryRequestMC">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="DetectorInventoryRequest" nillable="true" type="q1:DetectorInventoryRequestDC" xmlns:q1="http://schemas.datacontract.org/2004/07/tcore.ATISDataContracts" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="ConnectionRequest" nillable="true" type="q2:ConnectionRequestDC" xmlns:q2="http://schemas.datacontract.org/2004/07/tcore.ATISDataContracts" />
but when I drill down to the wsdl from my svc, and I copy/paste the schema import, I notice the message contract are missing, although the "q1:" etc.. are correct. My schema looks like this.
<xs:schema elementFormDefault="qualified" targetNamespace="http://ws.tcore.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://ws.tcore.com">
<xs:import schemaLocation="http://localhost:9305/mex?xsd=xsd1" namespace="http://schemas.datacontract.org/2004/07/tcore.ATISDataContracts" />
<xs:import schemaLocation="http://localhost:9305/mex?xsd=xsd0" namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
<xs:element name="DetectorInventoryRequest" nillable="true" type="q1:DetectorInventoryRequestDC" xmlns:q1="http://schemas.datacontract.org/2004/07/tcore.ATISDataContracts" />
<xs:element name="ConnectionRequest" nillable="true" type="q2:ConnectionRequestDC" xmlns:q2="http://schemas.datacontract.org/2004/07/tcore.ATISDataContracts" />
For the most part it looks the same. How can I get my MessageContract elements to appear in the schema?
Here is a sample of a message contract c# code
namespace tcore.ATISDataContracts
{
[MessageContract(IsWrapped = false)]
public class ASICDetectorInventoryRequestMC
{
[MessageHeader]
public ConnectionRequestDC ConnectionRequest;
[MessageBodyMember]
public DetectorInventoryRequestDC DetectorInventoryRequest;
}
}
Their schema shows the complex type, but my derived schema only show the element and not the complex type. What am I doing wrong here? Any help or tips is appreciated.
Thanks for the help,
~ck in San Diego
By default when your WSDL files are generated parts of the schema are split up into other import files, which will not likely correspond with imports that may have been used originally (in the client-provided WSDL file, for example). If you navigate to the imported XSD files (http://localhost:9305/mex?xsd=xsd1, for instance) you should find some of the elements you seem to be missing.

XSD, restrictions and code generation

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.

Categories

Resources