使用VBscript从节点和子节点的XML中提取数据
这里是第一张海报,对VBscript有些新手。我真的需要你们这些知道第二天性的人的帮助。 我尝试了一些相关的信息,希望不要太多 我一直在努力让它发挥作用,经过几天的尝试和十几次的代码迭代,我终于伸出了手。我还没有找到从XML文档中的多个级别(NOE和chidlren)提取数据的示例 我的任务是使用VBScript从XML文件中提取数据。 具体项目有:年度、账号、当前到期金额、是否拖欠?(正确/错误)和格式化的认股权证编号 XML文件的格式如下所示,其中包含1000到10000多个节点,其中包含大量的“misc”节点使用VBscript从节点和子节点的XML中提取数据,xml,vbscript,Xml,Vbscript,这里是第一张海报,对VBscript有些新手。我真的需要你们这些知道第二天性的人的帮助。 我尝试了一些相关的信息,希望不要太多 我一直在努力让它发挥作用,经过几天的尝试和十几次的代码迭代,我终于伸出了手。我还没有找到从XML文档中的多个级别(NOE和chidlren)提取数据的示例 我的任务是使用VBScript从XML文件中提取数据。 具体项目有:年度、账号、当前到期金额、是否拖欠?(正确/错误)和格式化的认股权证编号 XML文件的格式如下所示,其中包含1000到10000多个节点,其中包含大
<BillData>
<BillHeader>
<Year>2010</Year>
<misc></misc>
<misc2></misc2>
<misc3></misc3>
<AcctNumber>0002566129</AcctNumber>
<misc4></misc4>
<PayAmounts>
<CurrentAmountDue>133.06</CurrentAmountDue>
<misc5></misc5>
</PayAmounts>
<misc6></misc6>
<HasDelinquents>true</HasDelinquents>
<WarrantInfo>
<FormattedWarrantNumber>201115447</FormattedWarrantNumber>
</WarrantInfo>
</BillHeader>
</BillData>
我在Stack上找到一篇文章,建议使用下面的技术,但一旦我超过两个值,它就不适用于我,而我有更多。我猜这是因为可以说CurrentAmountDue和FormattedWarrance是XML中更深层次的
strQuery = "/BillData/BillHeader/ " & _
"[name()='Year' or name()='AccountNumber' or name()='HasDelinquents' or name()='CurrentAmountDue' or name()='FormattedWarrantNumber']"
令我惊讶的是,我能够让它返回一些值,但不是所有值都在同一个循环中,所以我的输出是关闭的(第一行只显示年份,最后一行丢失),并且只是一个逗号
strQuery = "/BillData/BillHeader/*"
Set colNodes=xmlDoc.selectNodes(strQuery)
For Each objNode in colNodes
' some lame if then statements that get the values, but this can't be the correct approach!
' these three items (Year, Account and HasDelinquents are under each BillHeader as far as I can tell, but this doesn't seem to be the most effective method.
if objNode.nodeName = "Year" then strYear = objNode.text
if objNode.nodeName = "Account" then strAccount = objNode.text
if objNode.nodeName = "HasDelinquents" then strHasDelq = objNode.text
for each CurrentAmt in objNode.SelectNodes("./CurrentAmountDue")
strCurrAmt = CurrentAmt.text
' i finally got a value here when I use msgbox to view it.'
next
for each WarrantNum in objNode.SelectNodes("./FormattedWarrantNumber")
strWarNum = WarrantNum.text
' getting this value also when I use msgbox to view it.
next
next
所以你可以看到我的尝试是徒劳的
我也试着在下面插入这一行。我把它放在最后一个之前,但它没有按预期工作。我还尝试插入一些IF-Then语句,在写入文件之前检查年份和帐户中的值,然后在写入文件后清除这些值。这几乎奏效了,但我的第一行和最后一行没有生成正确的数据
objFileToWrite.WriteLine(strYear & "," & strAccount & "," & strCurrAmt & "," & strHasDelq & "," & strWarNum)
好了,现在你对我的史前编码尝试感到好笑,你能帮我一把吗?:)
如果还需要什么,请告诉我。
谢谢你的时间。我知道你们中的一些人可能可以轻松地解决这个问题。你只会得到
年和拖欠的节点
,因为节点CurrentAmountDue
和FormattedWarrandNumber
不是/BillData/BillHeader
的直接子节点,并且没有名为AccountNumber
的节点(正确的节点名称应该是AcctNumber
)。要从XML树中的任意位置选择节点,请尝试以下表达式:
//*[name()='Year' or name()='AcctNumber' or name()='HasDelinquents' or name()='CurrentAmountDue' or name()='FormattedWarrantNumber']
由于节点CurrentAmountDue
和FormattedSecurityNumber
不是/BillData/BillHeader
的直接子节点,因此只会获得节点Year
和HasAbrables
,并且没有名为AccountNumber
的节点(正确的节点名称应为AcctNumber
)。要从XML树中的任意位置选择节点,请尝试以下表达式:
//*[name()='Year' or name()='AcctNumber' or name()='HasDelinquents' or name()='CurrentAmountDue' or name()='FormattedWarrantNumber']
针对问题前半部分的低技术“设计模式”-
创建并写入.CSV/.TXT文件-是:
Get an FSO
Open traget file for writing
WriteLine Header (optional)
Loop over your data to export
Create empty Array (elements ~ columns)
Fill elements (if possible)
WriteLine Join(Array, Delimiter) to traget file
Close file
代码:
Option Explicit
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
Dim sFSpec : sFSpec = "..\data\step00.csv"
Dim sDelim : sDelim = ";"
Dim aFields : aFields = Split("Yr ANum Amnt Delq FWNum")
Dim oTS : Set oTS = oFS.CreateTextFile(sFSpec)
Dim nRecs : nRecs = 10
Dim nRec
oTS.WriteLine Join(aFields, sDelim)
For nRec = 1 To nRecs
ReDim aData(UBound(aFields))
aData(0) = nRec
If nRec Mod 2 Then aData(1) = "odd"
oTS.WriteLine Join(aData, sDelim)
Next
oTS.Close
WScript.Echo oFS.OpenTextFile(sFSpec).ReadAll()
输出:
Yr;ANum;Amnt;Delq;FWNum
1;odd;;;
2;;;;
3;odd;;;
4;;;;
5;odd;;;
6;;;;
7;odd;;;
8;;;;
9;odd;;;
10;;;;
请标出两者之间的区别
oTS.WriteLine Join(aData, sDelim)
及
第二部分(在结构化XML上循环)的框架应该
像这样
Get an msxml2.domdocument
Configure
Load .XML file
If error
deal with it
Else
use top level XPath to get your top level nodelist
Loop nodelist
handle sub-parts
End If
代码:
Option Explicit
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
Dim sFSpec : sFSpec = oFS.GetAbsolutePathName("..\data\step01.xml")
WScript.Echo oFS.OpenTextFile(sFSpec).ReadAll()
Dim oXD : Set oXD = CreateObject("msxml2.domdocument")
oXD.setProperty "SelectionLanguage", "XPath"
oXD.async = False
oXD.load sFSpec
If oXD.parseError.errorCode Then
WScript.Echo "fail", sFSpec
WScript.Echo oXD.parseError.reason
Else
WScript.Echo "ok", sFSpec
Dim ndlBills : Set ndlBills = oXD.selectNodes("/Bills/BillData/BillHeader")
If ndlBills.length Then
WScript.Echo ndlBills.length, "bill nodes"
Dim ndBill
For Each ndBill In ndlBills
Dim ndSub
Set ndSub = ndBill.selectSingleNode("Year")
If ndSub Is Nothing Then
WScript.Echo "no Year"
Else
WScript.Echo "Year", ndSub.text
End If
Set ndSub = ndBill.selectSingleNode("PayAmounts/CurrentAmountDue")
If ndSub Is Nothing Then
WScript.Echo "no Amount"
Else
WScript.Echo "Amount", ndSub.text
End If
Next
End If
End If
输出:
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<BillData>
<BillHeader>
<Year>2012</Year>
</BillHeader>
</BillData>
<BillData>
<BillHeader>
<PayAmounts>
<CurrentAmountDue>123.45</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
</Bills>
ok E:\trials\SoTrials\answers\19571565\data\Step01.xml
2 bill nodes
Year 2012
no Amount
no Year
Amount 123.45
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<BillData>
<BillHeader>
<Year>2012</Year>
</BillHeader>
</BillData>
<BillHeader>
<Year>0000</Year>
<PayAmounts>
<CurrentAmountDue>0.0</CurrentAmountDue>
</PayAmounts>
<junk/>
</BillHeader>
<BillData>
<BillHeader>
<PayAmounts>
<CurrentAmountDue>123.45</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
<BillData>
<BillHeader>
<Year>2013</Year>
<PayAmounts>
<CurrentAmountDue>47.11</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
</Bills>
ok E:\trials\SoTrials\answers\19571565\data\Step02.xml
3 bill nodes
Yr,ANum,Amnt,Delq,FWNum
2012,,,,
,,123.45,,
2013,,47.11,,
输出:
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<BillData>
<BillHeader>
<Year>2012</Year>
</BillHeader>
</BillData>
<BillData>
<BillHeader>
<PayAmounts>
<CurrentAmountDue>123.45</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
</Bills>
ok E:\trials\SoTrials\answers\19571565\data\Step01.xml
2 bill nodes
Year 2012
no Amount
no Year
Amount 123.45
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<BillData>
<BillHeader>
<Year>2012</Year>
</BillHeader>
</BillData>
<BillHeader>
<Year>0000</Year>
<PayAmounts>
<CurrentAmountDue>0.0</CurrentAmountDue>
</PayAmounts>
<junk/>
</BillHeader>
<BillData>
<BillHeader>
<PayAmounts>
<CurrentAmountDue>123.45</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
<BillData>
<BillHeader>
<Year>2013</Year>
<PayAmounts>
<CurrentAmountDue>47.11</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
</Bills>
ok E:\trials\SoTrials\answers\19571565\data\Step02.xml
3 bill nodes
Yr,ANum,Amnt,Delq,FWNum
2012,,,,
,,123.45,,
2013,,47.11,,
或者——从长远来看可能更好
定义查询数组(按字段顺序)
Dim aQueries:aQueries=数组(_
“年”_
,“应付金额/当前应付金额”_
)
将最里面的循环减少为
Dim ndBill
For Each ndBill In ndlBills
oTS.WriteLine Join(getData(ndBill, aQueries), sDelim)
Next
定义getData()
针对问题前半部分的低技术“设计模式”-
创建并写入.CSV/.TXT文件-是:
Get an FSO
Open traget file for writing
WriteLine Header (optional)
Loop over your data to export
Create empty Array (elements ~ columns)
Fill elements (if possible)
WriteLine Join(Array, Delimiter) to traget file
Close file
代码:
Option Explicit
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
Dim sFSpec : sFSpec = "..\data\step00.csv"
Dim sDelim : sDelim = ";"
Dim aFields : aFields = Split("Yr ANum Amnt Delq FWNum")
Dim oTS : Set oTS = oFS.CreateTextFile(sFSpec)
Dim nRecs : nRecs = 10
Dim nRec
oTS.WriteLine Join(aFields, sDelim)
For nRec = 1 To nRecs
ReDim aData(UBound(aFields))
aData(0) = nRec
If nRec Mod 2 Then aData(1) = "odd"
oTS.WriteLine Join(aData, sDelim)
Next
oTS.Close
WScript.Echo oFS.OpenTextFile(sFSpec).ReadAll()
输出:
Yr;ANum;Amnt;Delq;FWNum
1;odd;;;
2;;;;
3;odd;;;
4;;;;
5;odd;;;
6;;;;
7;odd;;;
8;;;;
9;odd;;;
10;;;;
请标出两者之间的区别
oTS.WriteLine Join(aData, sDelim)
及
第二部分(在结构化XML上循环)的框架应该
像这样
Get an msxml2.domdocument
Configure
Load .XML file
If error
deal with it
Else
use top level XPath to get your top level nodelist
Loop nodelist
handle sub-parts
End If
代码:
Option Explicit
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
Dim sFSpec : sFSpec = oFS.GetAbsolutePathName("..\data\step01.xml")
WScript.Echo oFS.OpenTextFile(sFSpec).ReadAll()
Dim oXD : Set oXD = CreateObject("msxml2.domdocument")
oXD.setProperty "SelectionLanguage", "XPath"
oXD.async = False
oXD.load sFSpec
If oXD.parseError.errorCode Then
WScript.Echo "fail", sFSpec
WScript.Echo oXD.parseError.reason
Else
WScript.Echo "ok", sFSpec
Dim ndlBills : Set ndlBills = oXD.selectNodes("/Bills/BillData/BillHeader")
If ndlBills.length Then
WScript.Echo ndlBills.length, "bill nodes"
Dim ndBill
For Each ndBill In ndlBills
Dim ndSub
Set ndSub = ndBill.selectSingleNode("Year")
If ndSub Is Nothing Then
WScript.Echo "no Year"
Else
WScript.Echo "Year", ndSub.text
End If
Set ndSub = ndBill.selectSingleNode("PayAmounts/CurrentAmountDue")
If ndSub Is Nothing Then
WScript.Echo "no Amount"
Else
WScript.Echo "Amount", ndSub.text
End If
Next
End If
End If
输出:
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<BillData>
<BillHeader>
<Year>2012</Year>
</BillHeader>
</BillData>
<BillData>
<BillHeader>
<PayAmounts>
<CurrentAmountDue>123.45</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
</Bills>
ok E:\trials\SoTrials\answers\19571565\data\Step01.xml
2 bill nodes
Year 2012
no Amount
no Year
Amount 123.45
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<BillData>
<BillHeader>
<Year>2012</Year>
</BillHeader>
</BillData>
<BillHeader>
<Year>0000</Year>
<PayAmounts>
<CurrentAmountDue>0.0</CurrentAmountDue>
</PayAmounts>
<junk/>
</BillHeader>
<BillData>
<BillHeader>
<PayAmounts>
<CurrentAmountDue>123.45</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
<BillData>
<BillHeader>
<Year>2013</Year>
<PayAmounts>
<CurrentAmountDue>47.11</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
</Bills>
ok E:\trials\SoTrials\answers\19571565\data\Step02.xml
3 bill nodes
Yr,ANum,Amnt,Delq,FWNum
2012,,,,
,,123.45,,
2013,,47.11,,
输出:
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<BillData>
<BillHeader>
<Year>2012</Year>
</BillHeader>
</BillData>
<BillData>
<BillHeader>
<PayAmounts>
<CurrentAmountDue>123.45</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
</Bills>
ok E:\trials\SoTrials\answers\19571565\data\Step01.xml
2 bill nodes
Year 2012
no Amount
no Year
Amount 123.45
<?xml version="1.0" encoding="utf-8" ?>
<Bills>
<BillData>
<BillHeader>
<Year>2012</Year>
</BillHeader>
</BillData>
<BillHeader>
<Year>0000</Year>
<PayAmounts>
<CurrentAmountDue>0.0</CurrentAmountDue>
</PayAmounts>
<junk/>
</BillHeader>
<BillData>
<BillHeader>
<PayAmounts>
<CurrentAmountDue>123.45</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
<BillData>
<BillHeader>
<Year>2013</Year>
<PayAmounts>
<CurrentAmountDue>47.11</CurrentAmountDue>
</PayAmounts>
</BillHeader>
</BillData>
</Bills>
ok E:\trials\SoTrials\answers\19571565\data\Step02.xml
3 bill nodes
Yr,ANum,Amnt,Delq,FWNum
2012,,,,
,,123.45,,
2013,,47.11,,
或者——从长远来看可能更好
定义查询数组(按字段顺序)
Dim aQueries:aQueries=数组(_
“年”_
,“应付金额/当前应付金额”_
)
将最里面的循环减少为
Dim ndBill
For Each ndBill In ndlBills
oTS.WriteLine Join(getData(ndBill, aQueries), sDelim)
Next
定义getData()
我将经历我尝试这种方法时的一个较旧的迭代,但似乎我没有在路径名中包含*,我将把它减少到您所能看到的程度,以查看我是否可以根据需要收集数据。感谢您的评论!我将经历我尝试这种方法时的一个较旧的迭代看起来我没有在路径名中包含*,我将把它简化为你所拥有的,看看我是否可以收集我所需要的数据。感谢你的评论!哇,那是另外一回事!感谢你花了这么多时间在这上面,我将阅读你列出的一些项目,如“连接”、数组项目、if-not语句,等等。这有点让人不知所措,但我会尝试并尝试遵循它,这样我就可以合并搜查令号码。哇,那是另外一回事!感谢你一直投入到这项工作中,我将阅读你列出的一些项目,如“连接”、数组项目、if not语句等。这有点让人不知所措,但我会尝试然后试着跟踪它,这样我就可以合并搜查令号码了。