3

我正在使用类似于以下内容的 xml 文件。然而,它是以下数千倍。我将使用 powershell 来解析 xml

我需要找到字符串“c:\”出现的所有任务的任务名称。虽然如果字符串可能只显示一个区域,这可能很容易,但它可以完全显示在整个任务中。在这个特定的任务中,我将 C:\ 放在了 4 个不同的时间。

我希望得到任务名称的输出,以及给定路径被引用的位置......

<Task ID="00000000" Name="Task name goes here" Active="0" NextEID="22" CacheNames="random" AR="0" TT="COS">
        <Info>
            <Description>
            </Description>
            <Notes>
            </Notes>
        </Info>
        <Parameters>
            <moreParameters>C:\pathGoesHere</moreParameters>
        </Parameters>
        <Schedules/>
        <Source HostID="0" Type="FileSystem" Path="C:\path" FileMask="[Parm:parameter].txt" DeleteOrig="0" NewFilesOnly="0" SearchSubdirs="0" Unzip="0" RetryIfNoFiles="0" UseDefRetryCount="1" UseDefRetryTimeoutSecs="1" UseDefRescanSecs="1" UDMxFi="1" UDMxBy="1" ID="11"/>
        <For ID="13">
            <Destination HostID="000000" Type="siLock" FolderID="" FolderType="4" FolderName="Home/[Parm:parameter]/" Subject="" FileName="[OnlyName]_[YYYY][MM][DD].bai" UseOrigName="0" ForceDir="1" OverwriteOrig="1" UseRelativeSubdirs="1" Zip="0" UseDefRetryCount="1" UseDefRetryTimeoutSecs="1" UseDefUser="1" UseDefClientCert="1" ID="12"/>
            <If ID="14">
                <When>
                    <Criteria>
                        <comp a="[ErrorCodeFile]" test="NEQ" b="0"/>
                    </Criteria>
                    <UpdOrig Action="d" ID="15"/>
                    <Destination HostID="0000000000" Type="Share" Path="C:\anotherCPath" FileName="[Parm:parameter]_[YYYY][MM][DD].bai" UseOrigName="0" ForceDir="1" OverwriteOrig="1" UseRelativeSubdirs="1" Zip="0" UseDefRetryCount="1" UseDefRetryTimeoutSecs="1" ID="17"/>
                </When>
            </If>
        </For>
        <If ID="19">
            <When>
                <Criteria>
                    <comp a="[ErrorCodeTask]" test="NNE" b="0"/>
                </Criteria>
                <Email HostID="385322183" Subject="[TaskStatus]-[TaskName]" Message="" AddressTo="email@address.com" Attachment = "C:\path\" UseDefRetryCount="1" UseDefRetryTimeoutSecs="1" ID="20"/>
            </When>
        </If>
    </Task>
4

2 回答 2

7

假设 XML 位于file.xml,然后XPath返回您的Name属性: String "C:\" 可能位于:

//Task[contains(text(), "C:\") or //*[contains(text(), "C:\")] or //*[@*[contains(., "C:\")]]]/@Name

说明:

  • Task标签的文字
  • 任何孩子的文字
  • 在任何孩子的任何属性中

PowerShell 示例:

#read xml
$xml = [xml](gc -Encoding utf8 .\test.xml) 

#process it
$xml | 
   Select-Xml '//Task[contains(text(), "C:\") or //*[contains(text(), "C:\")] or //*[@*[contains(., "C:\")]]]/@Name' | 
   % { $_.Node."#text" }
于 2012-08-14T17:14:35.120 回答
1

当您转换为 [xml] 时,您可以使用非常好的“属性”语法访问所有内容。具有相同标签的多个节点将作为数组公开。然后,您可以使用 InnerXml 属性获取定义当前节点的原始 XML 字符串。然后你只需要对你的搜索字符串做一个简单的“-like”匹配。

假设您在一个文件中的单个“任务”节点下有多个“任务”节点:

$tasks = [xml] (Get-Content .\Tasks.xml)
$tasks.Tasks.Task |?{ $_.InnerXml -like '*C:\*' } | select -expand Name

或者,如果多个文件中的每个文件中都有一个任务节点:

dir *.xml |%{ [xml] (Get-Content $_) } |?{ $_.Task.InnerXml -like '*C:\*' } | select -expand Name

这些将为您提供任务名称。获取节点中包含搜索字符串的每一行有点棘手。这是一个 hacky 正则表达式方法(我知道我知道,不要用正则表达式解析 XML ......)。同样,假设每个 XML 文件中有一个 Task 节点:

$taskXmls = dir *.xml |%{ [xml](Get-Content $_) }

foreach($taskXml in $taskXmls)
{
   if($taskXml.Task.InnerXml -like '*C:\*')
   {
       $hits = [Regex]::Matches($taskXml.Task.InnerXml, '<[^<]*C:\\[^>]*>')
       $hitList = $null
       if($hits)
       {
            $hitList = $hits | select -expand Value
       }
       new-object psobject -prop @{TaskName = $taskXml.Task.Name; Hits = $hitList}
   }
}
于 2012-08-15T20:05:14.550 回答