You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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表

CurrentNext
Initial1
12
13
14
23
24
34

问题根源与解决方案

问题核心

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

优化点说明

  1. 类型转换:通过.text属性将XML属性对象转为字符串,匹配游标字符型字段的要求。
  2. 逻辑简化:用iif函数统一处理from属性为空的情况,避免嵌套判断,代码更简洁。
  3. 变量复用:复用loAttrItem变量,减少重复调用getNamedItem,提升执行效率。
  4. 注释优化:添加中文注释,更易理解代码逻辑。

内容的提问来源于stack exchange,提问作者DizzleBeans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:55:17