2016-07-29 172 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

相關問題