I have an XSD schema with a nonNegativeInteger type that is restricted with a pattern (\d{2}) and try to validate an XML file, but get error 6937:
XML Validation: The canonical form of the value '01' is not valid according to the specified type. This can result from the use of pattern facets on non-string types or range restrictions or enumerations on floating-point types. Location: /*:xy[1]/*:Item1[1]/*:Field1[1]
CREATE XML SCHEMA COLLECTION dbo.XY_SCHEMA
AS'
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:simpleType name="Int_Abs_02">
<xs:restriction base="xs:nonNegativeInteger">
<xs:minInclusive value="01"/>
<xs:maxInclusive value="99"/>
<xs:pattern value="\d{2}"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="Item1">
<xs:sequence>
<xs:element name="Field1">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="Int_Abs_02"/>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="xy">
<xs:complexType>
<xs:sequence>
<xs:element name="Item1" type="Item1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>';
GO
DECLARE #xy XML(dbo.XY_SCHEMA)
SELECT #xy = '
<xy xsi:noNamespaceSchemaLocation="XY" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Item1>
<Field1>01</Field1>
</Item1>
</xy>'
I guess the canonical form is '1' which then is not using the given pattern?
I have read the MS documentation regarding Canonical Forms and Pattern Restrictions.
Is there any way I can make this work without changing the XML or XSD?
I'm using SQL Server 2014.
This is legal according to the XSD spec, but it makes life very difficult and is best avoided. If you want the value "01" to be valid, but "1" to be invalid, then in all probability the value you are dealing with is not really an integer at all, but a string made up of digits. (Compare phone numbers, where leading zeros are significant, and arithmetic is meaningless).
If it really is a number, for example a day of the month, then it's best to allow the leading zero to be omitted. If it isn't a number, but is some kind of code, then it's best to define it as a string that matches a regex.
Related
Check #lptr's comment for solution
I have this piece of XML from which I need to extract the values and ids using SQL Server:
<root>
<field id="1" value="gfjsdgfdjy duahsd "absdjsd"" />
<field id="37" value="ysgfdyua" />
<field id="13" value="asdas" />
<field id="73" value="fgdgfd" />
<field id="adsf" value="fdsa" />
</root>
This is what I use to extract the values and ids from that XML, which is stored into variable #test, and insert them into a temp table:
insert into #tmp (field, val)
select field.value('#id', 'nvarchar(100)') as fieldID,
field.value('#value', 'nvarchar(200)') as val
from #test.nodes('root/field') A(field)
That query works fine until there's a value that has double quotes like in the example above, which throws the followig error: XML parsing: line 1, character 108, whitespace expected
Any way of working around that?
I have to mention that I do not create these XMLs by hand, but get them from a DB, so any mistakes in their creation is not my fault.
Conformant XML parsers are required to report all well-formedness errors, so any conformant XML parser will reject this ill-formed XML.
You can sometimes get around this by using parsers (which are not conformant XML parsers) that attempt to repair errors. However, I don't know if any of them are capable of handling this particular problem, Note that in the general case it can't be detected, consider
<root>
<field id="1" value="some " inner " 3" />
<field id="2" value="some " inner= " 3" />
</root>
The second field is well-formed XML.
Whenever a supplier provides you with ill-formed XML, you need to complain, as you would with any other product defect. Usually I have found suppliers very responsive to such error reports. It's surprising how often the XML export capability was entrusted to some junior programmer with no XML knowledge or experience, even if the company concerned is a very professional outfit.
Introduction
Here below there are 2 very simplified versions of xml documents in a XML column on a SQL Server 2014 production server.
To start solving performances issues with this XML field I have created an XSD.
Issue to resolve
One issue is left over (see examples below):
- An element with the name "ProjectNr"
- is Always unique within a specific XML document
- But can be found on one of 2 different locations
Question
My question is two-folded:
- Can this issue be solved
- And if so, how?
XML documents
XML document, type 1:
<Project>
<ID>1</ID>
<Name>1</Name>
<ProjectNr>1</ProjectNr>
</Project><br/><br/>
XML document, type 2:
<Project>
<ProjectNr>1</ProjectNr>
<ID>1</ID>
<Name>1</Name>
</Project>
The all compositor allows some flexibility in the ordering, and ensures that each element occurs with the desired amount of occurrences.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="Project">
<xs:complexType>
<xs:all>
<xs:element name="ProjectNr" type="xs:string"/>
<xs:element name="ID" type="xs:string"/>
<xs:element name="Name" type="xs:string"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
Both documents are valid against the above schema (assuming the two <br/> in the question are typos, because document 1 would otherwise not be wellformed).
Consider the following simplified XML schema collection
CREATE XML SCHEMA COLLECTION CD.AcceptMessageSchema AS '
<xs:schema xmlns="http://schemas.microsoft.com/Sql/2008/05/Procedures/Submit"
xmlns:ns1="http://schemas.microsoft.com/Sql/2008/05/Procedures/Submit"
xmlns:b="http://schemas.microsoft.com/BizTalk/2003"
targetNamespace="http://schemas.microsoft.com/Sql/2008/05/Procedures/Submit"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="AcceptMessage">
<xs:complexType>
<xs:sequence>
<xs:element name="MessagePayload" type="xs:string"/>
<xs:element name="PatientIdentifiers">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="ID" type="ID">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
and the following Stored Procedure definition
create procedureSubmit.AcceptMessage_DEV #AcceptMessage xml(CD.AcceptMessageSchema)
as
Insert into blah...
...stored proc guts go here...
You'll notice that the single paramter is defined associated to the Schema Collection. My assumption was that given the association to the SchemaCollection, you would be able to call the Stored Procedure by sending in something like the following:
<AcceptMessage xmlns="http://schemas.microsoft.com/Sql/2008/05/Procedures/Submit" xmlns:biztalk="http://InteriorHealth.BizTalk.CDX.Schemas.SQLSubmit.AcceptMessage" xmlns:ns0="http://microsoft.com/HealthCare/HL7/2X" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MessagePayload>
<![CDATA[somepayloaddata]]>
</MessagePayload>
<PatientIdentifiers>
<ID OID="2.16.840.1.113883.4.50" Value="3454545" AssigningAuthorityName="Patient Health Number" />
<ID OID="2.16.840.1.113883.3.277.1.73" Value="4545454" AssigningAuthorityName="Patient EMR Number" />
</PatientIdentifiers>
</AcceptMessage>
and it would work over a WCF-SQL send port.
The strange this is, if I call the stored procedure in SSMS:
EXEC Submit.AcceptMessage #AcceptMessage = ' <AcceptMessage xmlns="http://schemas.microsoft.com/Sql/2008/05/Procedures/Submit" xmlns:biztalk="http://InteriorHealth.BizTalk.CDX.Schemas.SQLSubmit.AcceptMessage" xmlns:ns0="http://microsoft.com/HealthCare/HL7/2X" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MessagePayload>
<![CDATA[somepayloaddata]]>
</MessagePayload>
<PatientIdentifiers>
<ID OID="2.16.840.1.113883.4.50" Value="3454545" AssigningAuthorityName="Patient Health Number" />
<ID OID="2.16.840.1.113883.3.277.1.73" Value="4545454" AssigningAuthorityName="Patient EMR Number" />
</PatientIdentifiers>
</AcceptMessage>';
it works just fine, but sending it over the wire via WCF-SQL I get the error:
The start element with name "MessagePayload" and namespace "http://schemas.microsoft.com/Sql/2008/05/Procedures/Submit" was unexpected. Please ensure that your input XML conforms to the schema for the operation.
This is the same thing that would happen before I applied the XML Scheam collection and defined the stored proc like this:
create procedureSubmit.AcceptMessage_DEV
#MessagePayload xml,
#PatientIdentifiers xml
as
If I were to then send in a request like above, it would give the error:
The start element with name "ID" and namespace "http://schemas.microsoft.com/Sql/2008/05/Procedures/Submit" was unexpected. Please ensure that your input XML conforms to the schema for the operation.
Because it didn't know what to do with the <ID> elements inside the <PatientIdentifiers> element.
I previously was wrapping all parameter data in CDATA tags and it worked, but I wanted the added schema validation if it would work.
So does this mean that when calling WCF-SQL, I basically have to CDATA everything inside the parameter elements, or is there something I'm missing?
Also, this is a messaging-only solution, no orchestrations.
How can I send nested XML into a SQL Stored proc in order to parse it and insert the data into tables?
In this specific case, I think a Table Value Parameter would be easier.
However, to answer what I think is your underlying question, you can pass an XML Type parameter either as CDATA or escaped Xml. The WCF Schema Element Type will always be xs:string though.
You are generating a schema for the SP, correct? You don't actually say.
My question relates to defining an XSD document. My specific issue is how to define the XSD so that when the XML is generated an element will have type="array".
Desired result would be something like:
<names type="array">
<name>
......
</name>
</names>
I have experimented using methods recommended on several forums, but from I have found it seems to me like there may not even be a type for array, which confuses me since a resulting XML element can have a type of array.
There are tools that will take an XSD and generate a sample XML document that adheres to the XSD, but you should understand that the primary purpose of an XSD is to validate an XML document.
This XSD will validate your XML document:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="names">
<xs:complexType>
<xs:sequence>
<xs:element name="name" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="type"/>
</xs:complexType>
</xs:element>
</xs:schema>
Note also that using a type="array" attribute-value pair is unconventional in the XML as type information is conveyed in the XSD in the content model for names and needn't be repeated explicitly in the XML document.
I have a Data Flow task with an XMLSource that references an XML Variable. The DataFlow task does recognize that there are x number of rows in the variable, but it only sees null values in every row:
The xml variable value:
<?xml version="1.0" encoding="utf-8"?>
<words>
<word>butter</word>
<word>crispy</word>
</words>
I used this source to generate the XSD within the XMLSource Editor - here is the auto-generated XSD:
<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="words">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="word" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The package compiles, executes, and processes all the rows in my XML, but only sees nulls rather than the actual text strings... Here is a shot of the DataViewer displaying 2 rows after reading the XML variable:
I discovered a way to get the values to populate... I'll post it here without giving myself points, in case anyone else encounters the same problem. This is just a "how to fix", but I'll give credit to anyone who can explain the "deeper whys".
Essentially, the XML needed to be wrapped in another root node:
<?xml version="1.0" encoding="utf-8"?>
<datarows>
<words>
<word>bacon</word>
<word>roasted</word>
<word>pork</word>
<word>edamame</word>
</words>
</datarows>
Even though the original XML I used was valid, SSIS wanted it to be wrapped in an additional root node, which I named datarows. Once I did that the package recognized the word values and completed successfully.
The associated schema:
<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="datarows">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="words">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="word" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I too had the same problem,. I was trying to consume a web service and import the output xml into a table in sql 2008.
The issue is really with the namespace that gets generated in the output xml by the webservice. The trick I have used was
1. Stored the output of the web service in a package level variable
2. Add a 'script task', to replace the unwanted name space.
3. Then used 'XMl Source Task' to import the data into a table.
-Kris...