Visual FoxPro中XML解析及节点数据存入游标问题求助
Visual FoxPro XML解析:属性提取类型不匹配问题解决
我在Visual FoxPro中做简单XML解析,需要把XML节点的属性值提取并存入游标。参考示例代码编写后,遇到loAttributeList.getNamedItem返回值是对象类型,插入游标时触发类型不匹配错误。刚接触XML与FoxPro DOM,希望解决类型问题或获取更优实现方案。
原代码
local lcXML as c lcXML = "C:\status_flow.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) create cursor Csrstatetransitions (Current c, [Next] c) parseXML(lcXML, lcAttrValue_stateValue, lcAttrValue_tranFrom, lcAttrValue_tranTo) ******************************************************* * this procedure will parse the xml in pcXMLFile and transform the XML into two cursors ***************************** 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 ? lcNodeName 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)) && 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 loAttributeList.getNamedItem(value_from) = "" insert into Csrstatetransitions values ("<Initial>", ; loAttributeList.getNamedItem(value_to)) else insert into Csrstatetransitions values ; (loAttributeList.getNamedItem(value_from), ; loAttributeList.getNamedItem(value_to)) endif endif endif endif endfor endproc
待解析XML内容
<Workflow> <State value="1"/> <State value="2"/> <State value="3"/> <State value="4"/> <Transition from="" to="1"/> <Transition from="1" to="2"/> <Transition from="1" to="3"/> <Transition from="1" to="4"/> <Transition from="2" to="3"/> <Transition from="2" to="4"/> <Transition from="3" to="4"/> </Workflow>
期望游标输出
Csrstatus表
| Status |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
Csrstatetransitions表
| Current | Next |
|---|---|
| Initial | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 3 |
| 2 | 4 |
| 3 | 4 |
问题根源与解决方案
问题核心
loAttributeList.getNamedItem()返回的是XML属性对象,并非直接的字符串值,直接插入字符型游标字段会触发类型不匹配错误。必须读取对象的.text或.value属性才能获取对应的字符串。
修改后的完整代码
local lcXML as c lcXML = "C:\status_flow.xml" local lcAttrValue_stateValue as c, lcAttrValue_tranFrom as c, lcAttrValue_tranTo as c lcAttrValue_stateValue = "value" && 要提取的状态属性名 lcAttrValue_tranFrom = "from" && 要提取的转移来源属性名 lcAttrValue_tranTo = "to" && 要提取的转移目标属性名 create cursor Csrstatus ([Status] c) create cursor Csrstatetransitions (Current c, [Next] c) parseXML(lcXML, lcAttrValue_stateValue, lcAttrValue_tranFrom, lcAttrValue_tranTo) ******************************************************* * 解析XML并将数据存入两个游标 ***************************** procedure parseXML(pcXMLFile, value_value, value_from, value_to) ***************************** local loXml, loRootNode, lcNodeName, lnType, lnNumNodes, ; loNodeList, loNode, loAttributeList, loAttrItem, lcFromVal, lcToVal loXml = createobject("MSXML2.DOMDocument.6.0") && 创建XML解析对象 loXml.async = .f. && 同步加载文档 loXml.load(pcXMLFile) && 加载XML文件 loRootNode = loXml.documentElement && 获取根节点 loNodeList = loRootNode.getElementsByTagName("*") && 获取所有节点 lnNumNodes = loNodeList.length && 节点总数 for lnPos = 0 to (lnNumNodes -1) && 遍历所有节点(XML节点索引从0开始) loNode = loNodeList.item(lnPos) lcNodeName = loNode.nodeName lnType = loNode.nodeType if lnType = 1 && 仅处理元素节点 loAttributeList = loNode.attributes if lcNodeName = "State" && 处理State节点,提取value属性到Csrstatus loAttrItem = loAttributeList.getNamedItem(value_value) if not isnull(loAttrItem) insert into Csrstatus values (loAttrItem.text) && 获取属性文本值 endif endif if lcNodeName = "Transition" && 处理Transition节点,提取from/to属性到Csrstatetransitions * 处理from属性,为空则替换为<Initial> loAttrItem = loAttributeList.getNamedItem(value_from) lcFromVal = iif(isnull(loAttrItem) or empty(loAttrItem.text), "<Initial>", loAttrItem.text) * 处理to属性 loAttrItem = loAttributeList.getNamedItem(value_to) if not isnull(loAttrItem) lcToVal = loAttrItem.text insert into Csrstatetransitions values (lcFromVal, lcToVal) endif endif endif endfor endproc
优化点说明
- 类型转换:通过
.text属性将XML属性对象转为字符串,匹配游标字符型字段的要求。 - 逻辑简化:用
iif函数统一处理from属性为空的情况,避免嵌套判断,代码更简洁。 - 变量复用:复用
loAttrItem变量,减少重复调用getNamedItem,提升执行效率。 - 注释优化:添加中文注释,更易理解代码逻辑。
内容的提问来源于stack exchange,提问作者DizzleBeans
相关产品推荐
相关产品推荐

