2016-07-29 170 views
3

因此,我一直在研究一个存储文件夹结构的XML文件,并且希望能够验证文件中存在的文件夹结构系统。虽然有很多方法可以尝试并执行“Resolve-Path”,“Get-ChildItems”等等......我希望能够构建XML结构中的路径,并将其放入字符串或其他内容中,以便我可以针对它运行Test-Path。听起来很容易吧?那么可能对于一些经验丰富的Powershell老兵来说可能是这样,但我对PS很陌生,并且有些困难将我的头围绕在这。如何获取PowerShell中的子节点的所有父节点

下面是XML的目录结构

<config> 
    <local> 
     <setup> 
      <folder name="FolderA" type="root"> 
       <folder name="FolderC"/> 
       <folder name="FolderB"> 
        <folder name="FolderD" type="thisone"/> 
       </folder> 
      </folder> 
     </setup> 
    </local> 
</config> 

如果孩子节点设置为FolderD的最终目标是建立类似这样的事情

FolderA\FolderB\FolderD 

这似乎是一个字符串的样本对我来说很明显,为了获得完整的路径,你必须从最后开始,向后走节点树,然后在那里我迷路了。 目的是从可能存在的多个路径中选择一条路径。因此,例如,我想检查FolderD的路径。所以我必须建立这个路径\ FolderA \ FolderB \ FolderD并忽略其余部分。

回答

3

最简单的方法可能是:

  • 识别目标叶子节点
  • 走到层次的循环,并建立从name属性值的路径,直到type=root节点被击中
$xmlDoc = [xml] @' 
<config> 
    <local> 
     <setup> 
      <folder name="FolderA" type="root"> 
       <folder name="FolderC"/> 
       <folder name="FolderB"> 
        <folder name="FolderD" type="thisone"/> 
       </folder> 
      </folder> 
     </setup> 
    </local> 
</config> 
'@ 

# Get the leaf element of interest. 
$leafNode = $xmlDoc.SelectSingleNode('//folder[@type="thisone"]') 

# Simply build up the path by walking up the node hierarchy 
# until an element with attribute type="root" is found. 
$path = $leafNode.name 
$node = $leafNode 
while ($node.type -ne 'root') { 
    $node = $node.ParentNode 
    $path = $node.name + '\' + $path   #'# (ignore this - fixes syntax highglighting) 
} 

# Output the resulting path: 
# FolderA\FolderB\FolderD 
$path 

原始答案,基于问题的原始形式:可能仍然对从元素属性自上而下构建路径感兴趣,使用递归

递归,你仍然可以采用自上而下的方法:

$xmlDoc = [xml] @' 
<folder name="FolderA"> 
    <folder name="FolderC"/> 
    <folder name="FolderB"> 
     <folder name="FolderD"/> 
    </folder> 
</folder> 
'@ 

# Define a function that walks the specified XML element's hierarchy to 
# down its leaf elements, building up a path of the values of the 
# specified attribute, and outputting the path for each leaf element. 
function get-LeafAttribPaths($xmlEl, $attrName, $parentPath) { 
    $path = if ($parentPath) { join-path $parentPath $xmlEl.$attrName } else 
          { $xmlEl.$attrName } 
    if ($xmlEl.ChildNodes.Count) { # interior element -> recurse over children 
    foreach ($childXmlEl in $xmlEl.ChildNodes) { 
     get-LeafAttribPaths $childXmlEl $attrName $path 
    } 
    } else { # leaf element -> output the built-up path 
    $path 
    } 
} 

# Invoke the function with the document element of the XML document 
# at hand and the name of the attribute from whose values to build the path. 
$paths = get-LeafAttribPaths $xmlDoc.DocumentElement 'name' 

# Output the resulting paths. 
# With the above sample input: 
# FolderA\FolderC 
# FolderA\FolderB\FolderD 
$paths 

# Test paths for existence. 
Test-Path $paths 
+0

@ todd1215:很高兴听到它;好点再循环 - 我已经更新了相应的答案。 – mklement0

2

我会写这样的说法:

$xmlDoc = [xml]'<folder name="FolderA"> 
    <folder name="FolderC"/> 
    <folder name="FolderB"> 
     <folder name="FolderD"/> 
    </folder> 
</folder>' 


function Get-XmlPath($node, $pathPrefix){ 
    $children = $node.SelectNodes('folder[@name]') 
    $path = [System.IO.Path]::Combine($pathPrefix, $node.name) 
    if ($children.Count) { 
     foreach($child in $children) { 
      Get-XmlPath $child $path 
     } 
    } else { 
     $path 
    } 
} 

Get-XmlPath $xmlDoc.DocumentElement | % { [PSCustomObject]@{Path = $_; Exist = Test-Path $_ } } 

在我的系统它产生:

Path      Exist 
----      ----- 
FolderA\FolderC    False 
FolderA\FolderB\FolderD  False 

更新为反映新的xm升结构

您可以缩小搜索选择的节点如下:

Get-XmlPath $xmlDoc.SelectSingleNode('//folder[@type="root"]') | % { [PSCustomObject]@{Path = $_; Exist = Test-Path $_ } } 

的关键是从正确的节点开始。你可以尝试其他选择器,如果这不适合:

#start from first folder node 
$xmlDoc.SelectSingleNode('//folder') 
#start from first folder node with root attribute 
$xmlDoc.SelectSingleNode('//folder[@type="root"]') 
+0

好吧,看看你给的例子,我写的XML看起来与我实际发布的略有不同。我的文件夹结构位于config/local/setup的XML路径中,我的文件夹元素也具有type属性。我在发布中更新了我的XML。更新的原因是因为当我对我的实际XML运行你的代码时,我得到了\ setup \ FolderA \ FolderC而不是像你的例子那样的FolderA \ FolderB。我对这个问题的误传表示歉意。 – todd1215

相关问题