Why my test xml is failing with very simple XSD Schema? - schema

I am a bit novice in xml schema. I would be grateful if somebody help me out to understand why my xml is not being validated with the schema:
Here is my Schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/testSchema" xmlns="http://www.example.org/testSchema">
<xs:element name="Employee">
<xs:complexType>
<xs:sequence>
<xs:element name="Name">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" />
<xs:element name="LastName" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Here is my test xml:
<?xml version="1.0" encoding="UTF-8"?>
<Employee xmlns="http://www.example.org/testSchema">
<Name>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
</Name>
</Employee>
I am getting following error by Eclipse xml editor/validator:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'Name'. One of '{Name}' is expected.
I could not understand what is wrong with this schema or my xml.

all u have to do is add elementFormDefault="qualified" and u will be fine. to understand this behavior, read "Are You Qualified?" section # http://msdn.microsoft.com/en-us/library/ms950796.aspx

Just add the elementFormDefault="qualified" to the schema attribues.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/testSchema"
elementFormDefault="qualified"
xmlns="http://www.example.org/testSchema">
And your original will work
<?xml version="1.0" encoding="utf-8"?>
<Employee xmlns="http://www.example.org/testSchema">
<Name>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
</Name>
</Employee>

Looks like you're failing to specify how to validate the FirstName and LastName elements; give the element specs for those type="xsd:string" (where xsd needs to be mapped to the XML Schema Datatypes namespace, of course) and all should be well.
But you are better off not nesting those elements so deep. Put them all at the same level and use ref="Name" to link them all together instead; it makes your schema much more flexible and usable.

Related

Decoding base64 encoded xml message returned from an SQL record in Biztalk

I am receiving a document in Biztalk, which contain some base64 encoded content inside an xml tag.
What I need, is to decode this content (which is a seperate XML document) and insert it into an in an envelope schema, to then be processed further.
The structure of the received document is like so:
<Polling xmlns="http://schemas.microsoft.com/Sql/2008/05/Polling/">
<PolledData>
<DataSet xmlns="http://schemas.datacontract.org/2004/07/System.Data">
<xs:schema id="NewDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element msdata:IsDataSet="true" name="NewDataSet">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="NewTable">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="ID" type="xs:string"/>
<xs:element minOccurs="0" name="hostUTC" type="xs:dateTime"/>
<xs:element minOccurs="0" name="msgType" type="xs:string"/>
<xs:element minOccurs="0" name="acknowledgment" type="xs:string"/>
<xs:element minOccurs="0" name="sendLog" type="xs:string"/>
<xs:element minOccurs="0" name="msgFormat" type="xs:string"/>
<xs:element minOccurs="0" name="msgbody" type="xs:base64Binary"/>
<xs:element minOccurs="0" name="fromID" type="xs:string"/>
<xs:element minOccurs="0" name="toID" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<NewDataSet xmlns="">
<NewTable>
<ID>123</ID>
<hostUTC>2018-11-08T14:53:24.11Z</hostUTC>
<msgType>INVOIC</msgType>
<msgFormat>Edifact</msgFormat>
<msgbody>base64encodedmessage...</msgbody>
<fromID>DKT:28504861</fromID>
<toID>KMDoioUBL</toID>
</NewTable>
</NewDataSet>
</diffgr:diffgram>
</DataSet>
</PolledData>
</Polling>
The base64 encoded content is located inside the tag.
I've already created the envelope schema, which has the following structure:
The message is received using a WCF-SQL adapter on a receive location. Currently no pipeline has been set up to process the message. In the 'Messages' tab of the adapter configuration it seems there is an option for base64 encoding, though I am not sure what this does or how it works exactly. When using the body setting here I get returned the above XML.
I'm not sure if this can be done without writing any code.
Reading this post on the subject, it seems that I need to write a custom pipeline component to handle the decoding. But first I would need to extract the content of the specific XML node.
I'm unsure how to approach this problem. I'd like to avoid using orchestrations if at all possible. Can this be done in standard Biztalk, or will I need to create custom functionality to handle this process?
Edit: XPath attempts
/Polling/PolledData[1]/*[namespace-uri()='http://schemas.datacontract.org/2004/07/System.Data' and local-name()='DataSet'][1]/*[namespace-uri()='urn:schemas-microsoft-com:xml-diffgram-v1' and local-name()='diffgram'][1]/*[namespace-uri()='' and local-name()='NewDataSet'][1]/*[namespace-uri()='' and local-name()='NewTable'][1]/*[namespace-uri()='' and local-name()='msgbody'][1]
/*[local-name()='Polling']/*[local-name()='PolledData']/*[local-name()='DataSet']/*[local-name()='diffgram']/*[local-name()='NewDataSet']/*[local-name()='NewTable']/*[local-name()='msgbody']
/Polling/PolledData/DataSet/diffgr:diffgram/NewDataSet/NewTable/msgbody
//*[msgbody]/text()

TypedPolling xsd to a simpler schema

I have a WCF SQL receive location and am able to get the relevant details from the database.
The xml looks like this:
<TypedPolling xmlns="http://schemas.microsoft.com/Sql/2008/05/TypedPolling/EmailNotifications">
<TypedPollingResultSet0>
<TypedPollingResultSet0>
<strPortName>port name 1</strPortName>
<LastRun_UTC>2016-01-29T10:20:10.083Z</LastRun_UTC>
</TypedPollingResultSet0>
<TypedPollingResultSet0>
<strPortName>portname 2</strPortName>
<LastRun_UTC>2016-01-29T11:37:38.82Z</LastRun_UTC>
</TypedPollingResultSet0>
<TypedPollingResultSet0>
<strPortName>portname3</strPortName>
<LastRun_UTC>2016-01-29T11:37:39.353Z</LastRun_UTC>
</TypedPollingResultSet0>
</TypedPollingResultSet0>
</TypedPolling>
The associated xsd is like this:
<?xml version="1.0" encoding="utf-16" ?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003"
targetNamespace="http://schemas.microsoft.com/Sql/2008/05/TypedPolling/EmailNotifications"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="TypedPolling">
<xs:complexType>
<xs:sequence>
<xs:element name="TypedPollingResultSet0">
<xs:complexType>
<xs:sequence>
<xs:element name="TypedPollingResultSet0">
<xs:complexType>
<xs:sequence>
<xs:element name="strPortName"
type="xs:string" />
<xs:element name="LastRun_UTC"
type="xs:dateTime" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I want to move data from this schema to a simpler one, whose xsd looks like this:
<?xml version="1.0" encoding="utf-16" ?>
<xs:schema xmlns="http://_024_EmailNotifications_Schemas.BizTalkDTADBExtractMod"
xmlns:b="http://schemas.microsoft.com/BizTalk/2003"
targetNamespace="http://_024_EmailNotifications_Schemas.BizTalkDTADBExtractMod"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Root">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded"
name="Notification">
<xs:complexType>
<xs:sequence>
<xs:element name="strPortName"
type="xs:string" />
<xs:element name="LastRun_UTC"
type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I created a transform shape and did a one to one mapping.
The source has 4 records but after the mapping I only get one record.
Can somebody please help me to figure out what am doing wrong?
Add a looping functoid to your map, with the input from the repeating TypedPollingResultSet0 and the output going to Notification.
Also, avoid copying and pasting XML from a browser -it will add undesireable characters (all the -s in your question), and it'd be a good idea to include some details about your map.

Convert XML to minimal branches to import into SQL Server with SSIS

I have a complex XML file that I am trying to import into SQL Server using SQL Server Data Tools. The issue is that there are many nested elements. The SSIS XML Source identifies each collection of children elements as their own table.
For example, I have the following (simplified) XML and XSD:
<?xml version="1.0" encoding="UTF-8"?>
<TrafficReport>
<TrafficElement>
<counts>
<vehicles>
<vehiclesElement>
<vehicleType>car</vehicleType>
<vehicleCount>15</vehicleCount>
</vehiclesElement>
<vehiclesElement>
<vehicleType>truck</vehicleType>
<vehicleCount>5</vehicleCount>
</vehiclesElement>
</vehicles>
<pedestrian>4</pedestrian>
</counts>
<description>
<type>Manual</type>
</description>
</TrafficElement>
</TrafficReport>
XSD:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Vehicle">
<xs:sequence>
<xs:element name="vehicleType" type="xs:string"/>
<xs:element name="vehicleCount" type="xs:short"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TrafficCounts">
<xs:sequence>
<xs:element name="vehicles">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="vehiclesElement" type="Vehicle"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="pedestrian" type="xs:short"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TrafficType">
<xs:sequence>
<xs:element name="type" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Traffic">
<xs:sequence>
<xs:element name="counts" type="TrafficCounts"/>
<xs:element name="description" type="TrafficType"/>
</xs:sequence>
</xs:complexType>
<xs:element name="TrafficReport">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="TrafficElement" type="Traffic"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Using the above XML and XSD, I have the following output tables from SSIS:
My problem with how SSIS creates the tables is that there are so many intermediate tables linking a single child element to the parent element.
My current solution for this is to create an XSL file that transforms the source data into the following XML:
<?xml version="1.0"?>
<TrafficReport>
<TrafficElement>
<vehiclesElement>
<vehicleType>car</vehicleType>
<vehicleCount>15</vehicleCount>
</vehiclesElement>
<vehiclesElement>
<vehicleType>truck</vehicleType>
<vehicleCount>5</vehicleCount>
</vehiclesElement>
<pedestrian>4</pedestrian>
<type>Manual</type>
</TrafficElement>
</TrafficReport>
Here is the XSL file I am using:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="TrafficReport">
<TrafficReport>
<xsl:for-each select="TrafficElement">
<TrafficElement>
<xsl:for-each select="counts/vehicles/vehiclesElement">
<vehiclesElement>
<vehicleType><xsl:value-of select="vehicleType" /></vehicleType>
<vehicleCount><xsl:value-of select="vehicleCount" /></vehicleCount>
</vehiclesElement>
</xsl:for-each>
<pedestrian><xsl:value-of select="counts/pedestrian" /></pedestrian>
<type><xsl:value-of select="description/type" /></type>
</TrafficElement>
</xsl:for-each>
</TrafficReport>
</xsl:template>
</xsl:stylesheet>
With the new XML, SSIS wants to create the following tables which are much easier to work with:
My solution is to pull any children elements to their parent elements, as long as it is a 1:1 relationship. The problem is that creating the XSL file is time consuming (over 750 elements) and I need to do this for multiple files.
Is there an automated way to compress XML to the minimum elements like I am doing manually? (Preferably within SSDT.)
Am I using the XML Source data task incorrectly with the first XML? When trying with the actual data, SSDT identifies over 100 output tables.
Any general suggestions on importing complex XML into SQL Server?
Since you have number of XML files, it's seems you need to use script component to process your XML files, where you can put your logic to extract required data from XML. Also you can LINQ to XML to process your files which is quite faster.

why did not got any error while validating my xml?

My Xml is not getting correctly validated against the XSD.
I expect the browser to through atleast some kind of generic error messages when i open xml file
My Xml file is below
note.Xml
<?xml version="1.0"?>
<note
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:SchemaLocation="note.xsd">
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
My Xsd file is below
note.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3schools.com"
xmlns="http://www.w3schools.com"
elementFormDefault="qualified"><xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
<xs:attribute name="to" type="xs:string" use="required"/>
</xs:complexType>
</xs:element></xs:schema>
Both the note.xml and note.xsd files are in the same folder.
Can somebody guide why i am not getting any error? So Can anyone help me how to validate my xml file with xsd? Thank you,
Three problems:
xsi:schemaLocation attribute value
should be a white-space separate
sequence of namespace URI and schema
document URI, like xsi:schemaLocation="http://www.w3schools.com note.xsd"
You wrote:
I expect the browser to through
atleast some kind of generic error
It's not clear that you are actually
using some validation tool. No
browser validates XML Schema when
you open an XML document.
Your schema targets the
http://www.w3schools.com namespace
URI, but your document is under null
(or empty) namespace URI. This will
end up in validation error, even if
you use the
xsi:noNamespaceSchemaLocation
instead of the xsi:schemaLocation
attribute. Maybe you want to add a
default namespace declaration in
your input source like
xmlns="http://www.w3schools.com"...

How to select the value of the xsi:type attribute in SQL Server?

Considering this xml document:
DECLARE #X XML (DOCUMENT search.SearchParameters) = '<parameters xmlns="http://www.educations.com/Search/Parameters.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<parameter xsi:type="category" categoryID="38" />
</parameters>';
I'd like to access the value of the attribute "type".
According to this blog post, the xsi:type attribute is special and can't be accessed by usual keywords/functions.
How can I do it?
PS: I tried with
WITH XMLNAMESPACES (
'http://www.educations.com/Search/Parameters.xsd' as p,
'http://www.w3.org/2001/XMLSchema-instance' as xsi)
SELECT #X.value('(/p:parameters/p:parameter/#xsi:type)[1]','nvarchar(max)')
but it didn't work.
Without specifying collection, this works fine for me:
DECLARE #X XML
SET #x = N'
<parameters xmlns="http://www.educations.com/Search/Parameters.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<parameter xsi:type="category" categoryID="38" />
</parameters>'
;
WITH XMLNAMESPACES
(
'http://www.educations.com/Search/Parameters.xsd' as p,
'http://www.w3.org/2001/XMLSchema-instance' as xsi
)
SELECT #X.value('(/p:parameters/p:parameter/#xsi:type)[1]','nvarchar(max)')
Could you please post contents of search.SearchParameters?
Update:
On schema-bound XML, this seems to be impossible.
You can cast your column into a freetype XML:
WITH XMLNAMESPACES
(
'http://www.educations.com/Search/Parameters.xsd' as p,
'http://www.w3.org/2001/XMLSchema-instance' as xsi
)
SELECT CAST(#X AS XML).value('(/p:parameters/p:parameter/#xsi:type)[1]','nvarchar(max)')
(but you won't be able to use XML indexes of any on your column), or perform a boolean check on a specific type:
WITH XMLNAMESPACES
(
'http://www.educations.com/Search/Parameters.xsd' as p
)
SELECT #X.query('(/p:parameters/p:parameter)[1] instance of element(*, p:category?)')
I know this is an old question, however I just ran into this issue yesterday and have found no obvious answer to this limitation in SQL. However, if you have control over the schema I have determined a work around.
Simply create an attribute on each subtype with the same name (widgetType in my example below).
Set each attribute to a simple type of xsi:string and put a restriction on it so the only value is the name of your subtype. Additionally, set this as the default value for the attribute.
If you bind this schema to your xml data column, you will always be able to query this attribute that essentially mirrors the xsi:type value.
I admit this is not ideal, but it is better than casting the value as untyped and losing the benefits of your indexes.
Here is an example:
<?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="widget"
type="baseWidget" />
<xs:complexType name="baseWidget"
abstract="true"></xs:complexType>
<xs:complexType name="widgetA">
<xs:complexContent>
<xs:extension base="baseWidget">
<xs:attribute name="widgetType"
default="widgetA">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="widgetA" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="widgetB">
<xs:complexContent>
<xs:extension base="baseWidget">
<xs:attribute name="widgetType"
default="widgetB">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="widgetB" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
If you were to put in an xml entry into a table bound to this schema without the widgetType attribute, SQL would automatically add it due to the default. It will always be available for you to query against.
<?xml version="1.0" encoding="utf-8"?>
<widget xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="widgetA"
widgetType="widgetA"
xmlns="http://tempuri.org/XMLSchema.xsd" />