You can also learn a bit about the XML which specifically resembles table data, by using the inverse VFP function of CursorToXML and inspecting the XML it generates:
Code:
Open Database (_samples+"Northwind\Northwind.dbc")
Use Customers
lcXML=""
CursorToXML("customers","lcXML",1,8,2,"")
That generates this XML (limited to 2 records by the 5th parameter nRecords:
[pre]<?xml version = "1.0" encoding="Windows-1252" standalone="yes"?>
<VFPData>
<customers>
<customerid>ALFKI</customerid>
<companyname>Alfreds Futterkiste</companyname>
<contactname>Maria Anders</contactname>
<contacttitle>Sales Representative</contacttitle>
<address>Obere Str. 57</address>
<city>Berlin</city>
<postalcode>12209</postalcode>
<country>Germany</country>
<phone>030-0074321</phone>
<fax>030-0076545</fax>
</customers>
<customers>
<customerid>ANATR</customerid>
<companyname>Ana Trujillo Emparedados y helados</companyname>
<contactname>Ana Trujillo</contactname>
<contacttitle>Owner</contacttitle>
<address>Avda. de la Constitución 2222</address>
<city>México D.F.</city>
<postalcode>05021</postalcode>
<country>Mexico</country>
<phone>(5) 555-4729</phone>
<fax>(5) 555-3745</fax>
</customers>
</VFPData>[/pre]
It's also not usíng what Greg mentioned: XSD - XML schema definition. Just like the books xml example from
is not using XSD. Such xml is lax and not specifying exactly what the xml elements contain.
For example the postalcode 12209 of ALFKI does not tell, whether it's the integer number 12209 or the string "12209". The postal code 05021 of ANATR with a leading zero hints at that column being a char data type, not integer or number or float - which it also could be. So such XML without XSD is not specifying what data types the elements have, just like it is with CSV.
So it can be turned into a cursor with the same guessing - infering is the offical term - of the data types. Well, when I'm precise a bit worse than in the CSV scenario, because in case of appending CSV to a cursor you have to do the job of defining the cursor and its columns with specific data types, in this case XMLTOCursor can only guess data type. The advantage is you don't have to predefine a cursor.
But let's see what happens with XMLTOCursor of such XML:
You see, VFPs guess is wrong, the 05021 is turned into 5021, because turning that XML without specific about the elements VFP uses an integer field for Postalcode. It would fail miserable with postalcodes like "WA1 1DP" as it is for a London customer in the Northwind database.
The problem can't be solved by a predefined cursor, XMLTOCursor will dump that and recreate one with the alias as given. So it's best, of course, to have XML with a schema. You can't choose to have that, though, you have to take what's given by the webservice. And that's one of the problems you'll be facing.
The other is, that XSDs, even if given, can be so complex, that VFP can't interpret them correctly with its outdated XML functionalities. Always have in mind VFP is from 2005, the last fixes of VFP were fropm 2009, but not releated to XML. So VFP is always behind the current state of the art XML, even when it uses Microsofts XML libraries, because the VFP XML related functions are based on and always use XML3 and XML4, nothing newer. That said, you get far with even that old functionalities, as data types haven't changed much since they were standardized.
Well, take that aside and see what XML you have to have to be able to turn it into one cursor, really. In the sense of a) having all data in that cursor after the parsing and b) having it in the right data types, ideally, too.
The XML structure is pretty formatted, here, so it's quite easy to spot that curesor fields are having tags for each fieldname, repeatedly, and are wrapped in a tag <customers>...</customers>, which verall is wrapped in a parent tag, here simply "VFPData" as it came from VFP. That's <catalog> in the books.xml case, so you see XMLToCursor does not look specifically for "VFPData" tags. But this structure has to exist, otherwise XMLToCursor fails, sometimes more miserably than other times and not always by throwing an error, it can fail quite silently.
So you don't get around what Piotr and Greg hinted at: Writing some request related conversion yourself, case by case. If you seek for general parsing of any XML, it's really best to find an XML library that is recent, at best with an active maintainer, which is true for Microsofts XML COM classes, for example.
The XSD VFP can create, when you use CursorToXML with appropriate parameterization can look like this:
Code:
<xsd:schema id="VFPData" xmlns:xsd="[URL unfurl="true"]http://www.w3.org/2001/XMLSchema"[/URL] xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="VFPData" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="customers" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="customerid">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="5"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="companyname">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="40"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="contactname" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="30"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="contacttitle" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="30"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="address" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="60"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="city" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="15"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="region" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="15"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
[highlight #FCE94F] <xsd:element name="postalcode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="10"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>[/highlight]
<xsd:element name="country" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="15"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="phone" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="24"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="fax" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="24"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
<xsd:anyAttribute namespace="[URL unfurl="true"]http://www.w3.org/XML/1998/namespace"[/URL] processContents="lax"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Here I highlited the portion that defines postalcode as a char(10) field, mainly, with data type definition as XML knows them, not a database, so char compares to xsd:string and <xsd:maxLength value="10"/> actually is comparable to a varchar(10) with up to 10 characters. So even with XSD you don't have a 1:1 representation of data types. I checked and XMLToCursor converts that back to a char(10) field, but don't rely on anything, you always will need to verify results about whether they have the quality you need and correspond to what is intended to come out.
Chriss