【问题标题】:How to write XML file depend on folder exist using PowerShell?如何使用 PowerShell 编写依赖于文件夹存在的 XML 文件?
【发布时间】:2019-08-24 01:09:20
【问题描述】:

我有 3 个文件夹,里面有一些文件和 3 个扩展名。 我想计算每个文件夹的文件总数,然后我想将输出写入 XML 文件。我试过了,但我只能将输出写入一个文件夹的 XML 文件。

$FindFolder = Get-ChildItem -Directory "D:\"
foreach ($folder in $FindFolder) {
    $jpg = Get-ChildItem -Name "D:\$folder" -Recurse -File -Include *.jpg |
           Measure-Object |
           ForEach-Object {$_.Count}
    $png = Get-ChildItem -Name "D:\$folder" -Recurse -File -Include *.png |
           Measure-Object |
           ForEach-Object {$_.Count}
    $gif = Get-ChildItem -Name "D:\$folder" -Recurse -File -Include *.gif |
           Measure-Object |
           ForEach-Object {$_.Count}

    # Write to xml file
    $Output = @"
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="Tool.css"?> 
<report>
    <heading>Final Report</heading>
        <foldername>$folder</foldername>
        <jpg>$jpg</jpg>
        <png>$png</png>
        <gif>$gif</gif>
</report>
"@

    $Output | Out-File "D:\Reports.xml" -NoNewline -Force
}

我上面这个脚本的输出是:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="Tool.css"?> 
<report>
    <heading>Final Report</heading>
        <foldername>folder1</foldername>
        <jpg>11</jpg>
        <png>11</png>
        <gif>0</gif>
</report>

预期的输出是:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="Tool.css"?> 
<report>
    <heading>Final Report</heading>
        <foldername>folder1</foldername>
        <jpg>11</jpg>
        <png>11</png>
        <gif>0</gif>

        <foldername>folder2</foldername>
        <jpg>1</jpg>
        <png>18</png>
        <gif>9</gif>

        <foldername>folder3</foldername>
        <jpg>16</jpg>
        <png>13</png>
        <gif>1</gif>
</report>

&lt;foldername&gt;NN&lt;/foldername&gt; 的总数取决于我有多少个文件夹。

【问题讨论】:

标签: xml powershell


【解决方案1】:

我认为您需要将工作分成三部分 - 标题数据、循环内部数据和任何页脚数据,然后只需使用 -Append 添加到文件中:

$mainFolder = "D:"

# Initialise file with header information
@"
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="Tool.css"?> 
<report>
    <heading>Final Report</heading>
"@ | Out-File "$mainFolder\Reports.xml" -Force

# Loop over the folders
$FindFolder = Get-ChildItem -Directory $mainFolder
foreach ($folder in $FindFolder) {
    $jpg = (Get-ChildItem -Name "$mainFolder\$folder" -Recurse -File -Include *.jpg).Count
    $png = (Get-ChildItem -Name "$mainFolder\$folder" -Recurse -File -Include *.png).Count
    $gif = (Get-ChildItem -Name "$mainFolder\$folder" -Recurse -File -Include *.gif).Count

# Append individual folder report to file
@"
        <foldername>$folder</foldername>
        <jpg>$jpg</jpg>
        <png>$png</png>
        <gif>$gif</gif>`n
"@ | Out-File "$mainFolder\Reports.xml" -Force -Append
}


# Append footer information to file
@"
</report>
"@ | Out-File "$mainFolder\Reports.xml" -NoNewline -Force -Append

在上面,我将主文件夹提取到一个变量中(只是为了稍微简化一下),然后使用标题信息初始化文件。然后循环遍历每个文件夹,并将报告部分添加到文件中。最后,它完成了文件。我稍微更改了换行符(从前两次写入中省略了 -NoNewLine,并在循环中添加了换行符 - 您可能希望更改格式以更好地满足您的需求。

【讨论】:

  • 非常感谢,这正是我需要的
  • 在您的代码中 Measure-Object 仅传递已经存在的 .Length/.Count 属性,并且可以省略。获取属性值的常用方法是通过管道传递到 | Select-Object -ExpandProperty Count 或更容易使用的 . dereference operator => $jpg = (Get-ChildItem -Name "$mainFolder\$folder" -Recurse -File -Include *.jpg).Count
  • 公平点@LotPings - 并使代码更易于阅读。在上面的答案中更新。
  • 我刚刚意识到你从 OP 那里拿走了那部分,而 Ansgar 的回答也包含 (...).count
【解决方案2】:

您发布的代码应该只为您提供 last 文件夹的结果,因为每次迭代都会覆盖输出文件。此外,您选择的 XML 结构很糟糕,因为它依赖于元素的顺序,而不是建立适当的层次结构。这样会好很多:

<?xml version="1.0" encoding="UTF-8"?>
<report>
    <heading>Final Report</heading>
    <folders>
        <folder name="folder1">
            <jpg>11</jpg>
            <png>11</png>
            <gif>0</gif>
        </folder>
        <folder name="folder2">
            <jpg>1</jpg>
            <png>18</png>
            <gif>9</gif>
        </folder>
        <folder name="folder3">
            <jpg>16</jpg>
            <png>13</png>
            <gif>1</gif>
        </folder>
    </folders>
</report>

简单的解决方案是在循环之前写入输出文件的顶部,循环之后的尾部,并且只在循环内写入文件夹部分:

@'
<?xml version="1.0" encoding="UTF-8"?>
<report>
    <heading>Final Report</heading>
    <folders>
'@ | Set-Content $report -Encoding UTF8

foreach ($folder in $FindFolder) {
    ...

    @"
        <folder name="folder2">
            <jpg>$jpg</jpg>
            <png>$png</png>
            <gif>$gif</gif>
        </folder>
"@ | Add-Content $report -Encoding UTF8
}

@'
    </folders>
</report>
'@ | Add-Content $report -Encoding UTF8

更好的方法是构造一个适当的 XML 对象,例如像这样:

$report = 'D:\Reports.xml'

$xml = New-Object Xml.XmlDocument

$preamble = $xml.CreateXmlDeclaration('1.0', 'utf-8', $null)
$xml.InsertBefore($preamble, $xml.DocumentElement) | Out-Null

$root = $xml.CreateElement('report')
$xml.AppendChild($root) | Out-Null

$folders = $xml.CreateElement('folders')
$xml.DocumentElement.AppendChild($folders) | Out-Null

并在循环中插入&lt;folder&gt; 节点:

foreach ($folder in $FindFolder) {
    $f = $xml.CreateElement('folder')
    $a = $xml.CreateAttribute('name')
    $a.Value = $folder.Name
    $f.Attributes.Append($a)

    $jpg = $xml.CreateElement('jpg')
    $jpg.InnerText = [string](Get-ChildItem $folder.FullName -Recurse -File -Filter '*.jpg').Count
    $f.AppendChild($jpg) | Out-Null

    ...

    $folders.AppendChild($f)
}

然后保存 XML 文档:

$xml.Save($report)

【讨论】:

  • 非常感谢你的回答非常棒
猜你喜欢
  • 2020-07-28
  • 2016-01-29
  • 2016-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 1970-01-01
相关资源
最近更新 更多