I have a huge XML file full of employees and information, and have a question.
Example of XML File:
<Employees>
<Employee>
<EmployeeID>blah</EmployeeID>
<FirstName>blah</FirstName>
<LastName>blah</LastName>
<MiddleName>blah</MiddleName>
.......... and on
</Employee>
........ and on
</Employees>
My schema, so far is like this:
<?xml version="1.0" encoding="utf-8"?>
<xsd:element name="Employees" sql:relation="The_Employees">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Employee">
<xsd:element name="EmployeeID" sql:field="EmpNo" type="xsd:integer"/>
<xsd:element name="FirstName" sql:field="FirstName">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:whiteSpace value="collapse"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
.......... and on
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
From my research, the root element is supposed to contain the relation with your table in the DB (for privacy sake, the name in this example is "The_Employees") So, I made that relation, and also made the sql:field for each column in the table because the column names are different than the XML Element tags in most cases. However, in what ways to do I relate each individual <Employee> tag to my table? Also, whilst validating the XML, it throws this error:
The content of 'Employee' must match (annotation?, (simpleType |
complexType)?, (unique | key | keyref)*)). A problem was found
starting at: element.
It seems like the validator is thinking that I am trying to split the content into two separate tables and therefore need to annotate that, but I am not. Any suggestions?
Just FYI: The end product here is going to be a VB.NET program which uses SQLXMLBulkLoad to load the data from the XML file into a fresh SQL Table.
Alright... the fix was simple and I am answering this so that someone in the future may refer to it. If you have a root element as well as each individual parent element under that root element and you are using BulkLoad, then you can set the root element to sql:is-constant = 1. This tells the schema that the root element exists, but to ignore it. Also, the above schema was ammended to:
<xsd:element name="Employees" sql:is-constant=1>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Employee" sql:relation="The_Employees">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="EmployeeID" sql:field="EmpNo" type="xsd:integer"/>
<xsd:element name="FirstName" sql:field="FirstName">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:whiteSpace value="collapse"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
.......... and on
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
Related
I have a simple XML:
DECLARE #x1 xml = '<r>
<o a="1">
<o a="2">
</o>
</o>
</r>';
And select the following:
SELECT r.o.value('(../#a)[1]','varchar(20)') FROM #x1.nodes('/r//o') r(o);
Everything is nice:
NULL
1
When I use typed XML:
CREATE XML SCHEMA COLLECTION [dbo].test AS '
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="r">
<xsd:complexType>
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="o" type="o" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="o">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="o" type="o" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="a" type="xsd:string" />
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>'
GO
DECLARE #x2 xml(dbo.test) = '<r>
<o a="1">
<o a="2">
</o>
</o>
</r>';
SELECT r.o.value('(../#a)[1]','varchar(20)') FROM #x2.nodes('/r//o') r(o);
I got the Error:
XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'
Why does the untyped XML works and the typed XML not?
It looks as though you well understand that this is not the usual problem of having to convince the parser that there is only one thing being passed into value(). This problem is specific to typed XML, as you have observed.
Using google I found this ancient blogpost with the promising text
rt is part of the XQuery 1.0/XPath 2.0 data model.
Most people get by that. The real fun starts when you do examples using untyped XML and XPath expressions with the text() node test. text() works just fine when using untyped XML, but fails against typed XML with simple content
It talks about the SQL Books Online and the SQL Server 2005 XML Best Practices paper, which I think is this book here. I haven't looked for a more up-to-date reference. But using what I found there I have been able to fix your problem: Simple replace
SELECT r.o.value('(../#a)[1]','varchar(20)') FROM #x2.nodes('/r//o') r(o);
with
SELECT r.o.value('fn:string(../#a)[1]','varchar(20)') FROM #x2.nodes('/r//o') r(o);
Basically, value() doesn't like being given values of a typed-xml-type, but wants strings. So we give it a string.
I just started learning XML today. I was trying to create a 'sample' XSD and populate it but.. I made up my data and it looks fine, but I can't make this schema work..
CREATE XML SCHEMA COLLECTION GenreTestSchema
AS
<?xml version = "1.0" encoding = "UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--create group for GENRELIST-->
<xsd:group name="GENRELISTGROUP">
<xsd:element name="GENRELIST">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="GENRE" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="REFERENCE" minOccurs="0" maxOccurs="100" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:group>
</xsd:schema>
Now If I remove this element
<xsd:element name="GENRELIST">
and all the code that goes with it so (element and complextype) then the schema works fine. I can't figure out what is wrong here and why it doesn't let me create this element?
Errorlog
Element <element> is not valid at location '/*:schema[1]/*:group[1]/*:element[1]'.
It talks about invalid location but I literally have no idea why?
Data sample
<GENRELIST xmlns="http://myGenres">
<GENRE GenreNo="1">
<GENRE>Fiction</GENRE>
<REFERENCE>Alien</REFERENCE>
</GENRE>
<GENRE GenreNo="2">
<GENRE>Tragedy</GENRE>
<REFERENCE>Titanic</REFERENCE>
</GENRE>
</GENRELIST>
The problem is that you're missing to take the namespace xmlns="http://myGenres" into account on the element GENRELIST.
So transform your anonymous complex type to a named type and use the namespace on it:
<?xml version = "1.0" encoding = "UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:gl="http://myGenres"
targetNamespace="http://myGenres"
elementFormDefault="qualified">
<xsd:complexType name="genrelist"> <!-- named type 'genrelist' -->
<xsd:sequence>
<xsd:element name="GENRE" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="REFERENCE" minOccurs="0" maxOccurs="100" />
</xsd:sequence>
</xsd:complexType>
<!--create group for GENRELIST-->
<xsd:element name="GENRELIST" type="gl:genrelist" /> <!-- applying the 'gl' namespace to named type 'genrelist' -->
</xsd:schema>
This way your XML will be validated.
For the purpose of targetNamespace look here and for
elementFormDefault look there.
I don't know why you're trying to create an xs:group (a "model group"). A model group is a reusable chunk of schema declarations that can be used in several places, handy when you have multiple elements with similar structure. It might sometimes make sense to have a group with only one reference to it, but it can't make sense to have a group with no references to it.
Now there's an additional (and related) problem). Typically when you start validating an instance document, the validator looks for a global element declaration whose name matches the root element of the instance. But you don't have a global element declaration in your schema; your declaration of GENRELIST isn't global because it is in a group.
I am manually creating an XSD file to import to MS SQL using the SQLXML Bulkload library.
I am setting up relationships in the annotation and would like to pass the primary key of the Parent table to the Child table as a foreign key. Is there away to do this without having the FK data already existing in the child data in the XML?
XML
<ParentExample projectId="testprojectId" serialNumber="XXXXXXX"/>
<ChildExample randomstuff="random">
XSD
<xsd:appinfo>
<sql:relationship name="ParenttoChild"
parent="ParentExample"
parent-key="projectId serialNumber"
child="ChildExample"
child-key="projectId serialNumber" /></xsd:appinfo>...
<xsd:element name="ParentExample" sql:relation="ParentExample"
maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="projectId" type="xsd:string" />
<xsd:attribute name="serialNumber" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="ChildExample" sql:relation="ChildExample"
maxOccurs="unbounded" sql:relationship="ParenttoChild">
<xsd:complexType>
<xsd:attribute name="projectId" type="xsd:string" />
<xsd:attribute name="serialNumber" type="xsd:string" />
<xsd:attribute name="randomstuff" type="xsd:string" />
</xsd:complexType>
</xsd:element>
Currently the result is that the projectId and serialNumber fields show up in the DB for the Child table, but the are not populating from the Parent. The data is null in the child table for the two foreign keys. Thank you for any help! Is there a way to populate the child table from the parent through the XSD?
Still learning about using XML in SQL Server 2008. It seems many of the examples I've seen demonstrating how to validate XML data using XML Schema Collection are validating XML of a known size. My problem is that the XML data that I'm working with can have 'X' number of Kit elements.
The validation works fine if there is just one kit, but if multiple <xsd:element name="Kit"> elements are in the XML then I get error:
XML Validation: Unexpected element(s): Kit. Location: /:KitStatus[1]/:Kits[1]/:Kit[2]*
My code:
CREATE XML SCHEMA COLLECTION [dbo].[KitStatusSchema] AS
N'<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="KitStatus" >
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ClientID"/>
<xsd:element name="Kits">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="NumberofKits"/>
<xsd:element name="Kit">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="PackageNumber"/>
<xsd:element name="KitNumber"/>
<xsd:element name="LocationNumber"/>
<xsd:element name="Status"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Is it possible for the validation to validate 1 or multiple Kits?
I have the following XML Schema:
CREATE XML SCHEMA COLLECTION test AS '
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="PointConf">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="GlobalFlags">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Order" type="OrderType"/>
<xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="OrderType">
<xsd:attribute name="value" type="xsd:int" />
</xsd:complexType>
</xsd:schema>
'
GO
Then I use it in this way:
DECLARE #xml xml(test)
SET #xml='<PointConf>
<GlobalFlags>
<Order value="1" />
</GlobalFlags>
</PointConf>'
SELECT #xml.value('(/PointConf/GlobalFlags/Order/#value)[1]','int')
SELECT gives me the following error:
XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type '(xs:int | xdt:anyAtomicType *) ?'
Without the xsd:any element in the schema the code above works without any errors. What am I doing wrong?
I got the select to work by using the statement
SELECT #xml.value('string(/PointConf[1]/GlobalFlags/Order[1]/#value)','int')
I understand the requirement for the [1] index on the Order node, as this can be a list, however I don't see why its required for the PointConf node.
The [1] needs to be used at the actual level where a list exists to restrict that list to a single return value
The string(...) turns the node set into a string (or empty string). I think this helps with the xsd:any although I'm not completely sure why - something to do with handling the possibility of the node Order being missing completely I think.
Update:
Investigating further:
SELECT #xml.value('string((/PointConf/GlobalFlags/Order/#value)[1])','int')
also works.
So its just the string function that's required to make it work in this instance.