I am looking to perform a simple XML parse in Visual FoxPro and extract the XML node values and attributes into cursors. I have found this webpage:
I am new to XML and the DOM with FoxPro so hopefully someone can help me further understand how to parse XML and extract values and attributes to foxpro cursors. If you see a better way to accomplish this compared to the loop structure I have in my code, feel free to share that as well. Otherwise, there are hopefully only some small changes needed in my code to get this to work.
The output of the two cursors should look something like:
Status |
---|
1 |
2 |
3 |
4 |
Current | Next |
---|---|
Initial | 1 |
1 | 2 |
1 | 3 |
1 | 4 |
2 | 3 |
2 | 4 |
3 | 4 |
CodePudding user response:
For the specified source you can just do:
oxml=CREATEOBJECT('msxml.domdocument')
oxml.load("D:\yoursource.xml")
XMLTOCURSOR(oxml.selectSingleNode('/Patients/States').xml,'States')
XMLTOCURSOR(oxml.selectSingleNode('/Patients/Transitions').xml,'Transitions')
for more complex xml you can use a xml parser -Check nfXml: https://github.com/vfpx/nfxml
CodePudding user response:
(I wouldn't use this at all, just replying because you asked where you made a mistake. I would definitely suggest Marco's code, or simply use Strextract() plus XMLToCursor())
In your code you are trying to insert a complete object but you need its 'value'.
Never ever create a data structure with just c, specify a length, ie:c(10)
Instead of using if someThing = .F. you could simply use if !someThing
Local lcXML As c
lcXML = "C:\temp\myxml.xml"
Local lcAttrValue_stateValue As c, lcAttrValue_tranFrom As c, lcAttrValue_tranTo As c
lcAttrValue_stateValue = "value" && attribute names for which the value will be added to cursor
lcAttrValue_tranFrom = "from"
lcAttrValue_tranTo = "to"
Create Cursor Csrstatus ([Status] c(10))
Create Cursor Csrstatetransitions (Current c(10), [Next] c(10))
parseXML(lcXML, lcAttrValue_stateValue, lcAttrValue_tranFrom, lcAttrValue_tranTo)
Procedure parseXML(pcXMLFile, value_value, value_from, value_to)
Local loXml, loRootNode, lcParentName, lcNodeName, lcValue, lcName, lnType, lnNumNodes, ;
loNodeList, loNode, lbHasChild, lcTagName, loChildNodeList, lnChildLen, lnPass, loChildNode, ;
loAttributeList, lcAttrName, lcAttrValue, lc, lnNumAttr, loParentNodeList, lnNumParentNodes
loXml = Createobject("MSXML2.DOMDocument.6.0") && create the xml parser object
loXml.Async = .F. && wait for teh document to be parsed and loaded
loXml.Load(pcXMLFile) && load the document into the object
loRootNode = loXml.documentElement && get the root element
loNodeList = loRootNode.getElementsByTagName("*") && get all nodes in document
lnNumNodes = loNodeList.Length && number of nodes in document
*? lnNumNodes
For lnPos = 0 To (lnNumNodes -1) && go through all nodes in loNodeList (note, array starting point 0 for XML nodes)
loNode = loNodeList.Item(lnPos)
lcNodeName = loNode.nodeName
loAttributeList = loNode.Attributes
lcAttrValue = loAttributeList.getNamedItem("value")
*? lcAttrValue_value
lnType = loNode.nodeType
If lnType = 1
If lcNodeName = "State" && if node name is "State", then we want to extract the nodes attribute into cursor
If Isnull(loAttributeList.getNamedItem(value_value)) = .F.
Insert Into Csrstatus Values ;
(loAttributeList.getNamedItem(value_value).Value) && doesnt work because type mismatch...
Endif
Endif
If lcNodeName = "Transition"
If Isnull(loAttributeList.getNamedItem(value_from)) = .F. ;
and Isnull(loAttributeList.getNamedItem(value_to)) = .F.
&& special case if 'from' node is empty
If Empty(loAttributeList.getNamedItem(value_from).Value)
Insert Into Csrstatetransitions Values ("<Initial>", ;
loAttributeList.getNamedItem(value_to).Value)
Else
Insert Into Csrstatetransitions Values ;
(loAttributeList.getNamedItem(value_from).Value, ;
loAttributeList.getNamedItem(value_to).Value)
Endif
Endif
Endif
Endif
Endfor
Endproc
CodePudding user response:
For more complex XML, take a look at the XMLAdapter class. It's designed to keep you from having to deal directly with the DOM.
Tamar