我正在尝试创建一个XML文件,该文件表示具有未知数量的嵌套目录和文件的分层目录结构。这个问题与我之前问过的一个问题有关,如何在给定初始启动目录的情况下循环遍历Foxpro中的嵌套目录,所以我到目前为止(见下文)的代码是基于这里的答案的结构。
*********************************
**** Variable initialization ****
*********************************
set asserts on
set date ymd
public loXml as MSXML2.DOMDocument60
public loRoot as MSXML2.IXMLDOMElement
public loNode as MSXML2.IXMLDOMElement
public loFile as MSXML2.IXMLDOMElement
public loFolder as MSXML2.IXMLDOMElement
public loSubFolder as MSXML2.IXMLDOMElement
public lcRootDir as String
public lcManifestNS as String
lcRootDir = "C:LoopTest" && user defined root directory
lcManifestNS = "http://www.randomnamespace.com/ServerManifest/1.1" && namespace which all elements int his document reside
***********************************
**** Creating the XML Document ****
***********************************
loXml = createobject("MSXML2.DOMDocument.6.0")
loRoot = loXml.createNode("Element", "au:Manifest", lcManifestNS) && root element
loRoot.setAttribute("Path", lcRootDir) && path attrubute of root element
GetFilesRecursively(lcRootDir) && builds all folder and file child nodes under the root element
loXml.appendChild(loRoot) && append everything within the root node to the document
*********************
** same xml output **
*********************
loXml.save('C:resultsex2_manifest_test.xml') && save the xml file to desired location
***************
** Functions **
***************
procedure getfilesrecursively(tcfolder)
assert ( vartype(m.tcfolder) = 'C' )
local lnfile, lafiles[1], lcfileorfolder, datemod && create local variables
for lnfile = 1 to adir(lafiles, addbs(m.tcfolder) + '*', 'd') && loop that will go through all direct items within initial directory
lcfileorfolder = lower(lafiles[m.lnfile, 1]) && this variable is the name of the item inside directory
if empty( strtran(m.lcfileorfolder,'.') ) && some items have names which are just . or .. etc, so ignore these items by restarting the loop
loop
endif
datemod = strtran(dtoc(lafiles[lnfile, 3]), '/', '-') + "T" + lafiles[lnfile, 4] && creating the datetime last modified value
if directory( addbs(m.tcfolder)+m.lcfileorfolder, 1 ) && if there is a subdirectory, re-run the main loop with updated file path
loFolder = loRoot.appendChild(loXml.createNode("Element", "au:Folder", lcManifestNS)) && folder node under root node
loFolder.setAttribute("Name", lcfileorfolder) && attrubutes for folder node
loFolder.setAttribute("Date", datemod)
getfilesrecursively(addbs(m.tcfolder)+m.lcfileorfolder)
else && if no further subdirectory, then insert the item into table
loFile = loFolder.appendChild(loXml.createNode("Element", "au:File", lcManifestNS)) && file node under folder node
loFile.setAttribute("Name", lcfileorfolder) && attributes for file node
loFile.setAttribute("Date", datemod)
endif
endfor
endproc
我在这段代码中遇到的主要问题是,所有的文件夹目录都放在根节点下,并且没有正确嵌套。我明白这是为什么,但我不清楚我该如何改变这种状况。是不是每次迭代都要创建一个新节点,然后附加到它上面?我只是习惯了FoxPro XML周围的语法,所以一些帮助解决这个问题将非常感激。此外,似乎根目录下的任何文件都被放在XML输出中的一个嵌套目录中。您可以从我的代码中看到原因。因此,最终,我希望纠正这些问题,使XML输出节点得到正确的嵌套。也许有一种不同的方法可以解决这个问题,所以如果你愿意,可以用一个全新的代码大纲来回答这个问题。
您可以使用ADIR()执行如下操作(请阅读代码后面的注释):
Local lcOutputFile, lcRoot
lcOutputFile = 'C:tempnestedDirs.xml'
lcRoot = Home()
GetTreeXML(m.lcRoot, m.lcOutputFile)
Procedure GetTreeXML(tcRootPath, tcOutput)
Local lcXML
Set Textmerge On To (m.tcOutput) Noshow
<au:Manifest xmlns:au="http://www.randomnamespace.com/ServerManifest/1.1" Path="<< ADDBS(m.tcRootPath) >>">
GetTree(m.tcRootPath,'myDirectories',0)
*!* Select * From myDirectories &&ORDER BY Filepath
*!* Use In 'myDirectories'
</au:Manifest>
Set Textmerge Off
Set Textmerge To
Return m.lcXML
Endproc
Procedure GetTree(tcPath, tcCursorName, tnLevel)
Local lcCurDir, ix, lcPath
Local Array laDirs[1]
lcCurDir = Addbs(m.tcPath)
If m.tnLevel = 0
Create Cursor (m.tcCursorName) (FilePath c(250), Level i)
Endif
Insert Into (m.tcCursorName) (FilePath,Level) Values (m.lcCurDir, m.tnLevel)
For ix = 1 To Adir(laDirs,m.lcCurDir+"*.*","DHS")
lcPath = m.lcCurDir+laDirs[m.ix,1]
If laDirs[m.ix,1]#"." And "D"$laDirs[m.ix,5]
GetTree(m.lcPath, m.tcCursorName, m.tnLevel+1)
Else
If laDirs[m.ix,1] != '..'
ProcessPath( m.lcPath, m.tnLevel, laDirs[m.ix,3], laDirs[m.ix, 4] )
Endif
Endif
Endfor
<< SPACE(2 * m.tnLevel) >></au:Folder>
Endproc
Procedure ProcessPath(tcPath, tnLevel, tdFileDate, tcFileTime)
Local lcName, lcDate
lcDate = Ttoc( Cast(m.tdFileDate As Datetime) + (Ctot(m.tcFileTime)-Ctot('0')), 3)
If Right(m.tcPath,2) == '.' && Directory
If m.tnLevel > 0 && Skip root
lcName = Justfname(Left(m.tcPath, Len(m.tcPath)-2))
<< SPACE(2 * m.tnLevel) >><au:Folder Name="<< m.lcName >>" Date="<< m.lcDate >>">
Endif
Else
lcName = Justfname(m.tcPath)
<< SPACE(2 * (m.tnLevel+1)) >><au:File Name="<< m.lcName >>" Date="<< m.lcDate >>"/>
Endif
Endproc
我不确定最终的XML。我遵循了你的格式。对我来说,它看起来有点尴尬,但如果这是你的清单的格式,那么它是好的(我无法浏览模式)。
无关,在你的代码中有变量声明为public,请忘记VFP中有一个"public"。几乎所有人都只将它用于在应用程序开始时创建的特定oApp对象(如果有的话)。相信我,使用它是危险的。
注意:VFP提供了一个名为Filer.dll的DLL。它包含一个activex 'Filer.FileUtil'。它可以收集文件夹和文件与一些过滤器应用(有超过简单*。*'文件骨架过滤器')。它返回带有原始大小写的结果,而不像adir()结果是全部大写。此外,您还可以获得文件的创建、修改和最后访问时间。
另一个是Scripting.FileSystemObject。但是,出于安全考虑,可能不会安装它。
如果Adir()对你来说很好,那么它是简单而快速的。
编辑:我后来注意到上面的代码会在末尾添加一个额外的au:Folder,而且它不会处理XML中不允许的字符。DOM处理将兼顾这两方面。下面是带有DOM的版本:Local lcOutputFile, lcRoot
lcOutputFile = 'C:tempnestedDirs.xml'
lcRoot = Home()
GetTreeXML(m.lcRoot, m.lcOutputFile)
Procedure GetTreeXML(tcRootPath, tcOutput)
Local loXML As "MSXML2.DOMDocument.6.0", loRoot As "MSXML2.IXMLDOMElement"
loXML = Createobject("MSXML2.DOMDocument.6.0")
loRoot = m.loXML.createNode("Element", "au:Manifest", "http://www.randomnamespace.com/ServerManifest/1.1")
loRoot.setAttribute("Path", m.tcRootPath)
GetTree(m.tcRootPath,'myDirectories',0, m.loXML, m.loRoot)
m.loXML.appendChild(m.loRoot)
m.loXML.Save(m.tcOutput)
Endproc
Procedure GetTree(tcPath, tcCursorName, tnLevel, toDOM, toParent)
Local lcCurDir, ix, lcPath, lcName, lcDate, loElement
Local Array laDirs[1]
lcCurDir = Addbs(m.tcPath)
For ix = 1 To Adir(laDirs,m.lcCurDir+"*.*","DHS")
lcName = laDirs[m.ix,1]
lcDate = Ttoc( Cast(laDirs[m.ix,3] As Datetime) + (Ctot(laDirs[m.ix,4])-Ctot('0')), 3)
If laDirs[m.ix,1]#"." And "D"$laDirs[m.ix,5]
lcPath = m.lcCurDir + laDirs[m.ix,1]
loElement = m.toDOM.createElement("au:Folder")
m.loElement.setAttribute("Name", m.lcName)
m.loElement.setAttribute("Date", m.lcDate)
m.toParent.appendChild(m.loElement)
GetTree(m.lcPath, m.tcCursorName, m.tnLevel+1, m.toDOM, m.loElement)
Else
If laDirs[m.ix,1] != '.' And laDirs[m.ix,1] != '..'
loElement = m.toDOM.createElement("au:File")
m.loElement.setAttribute("Name", m.lcName)
m.loElement.setAttribute("Date", m.lcDate)
m.toParent.appendChild(m.loElement)
Endif
Endif
Endfor
Endproc