Xml 如果元数据相同,如何组合成单个属性?

Xml 如果元数据相同,如何组合成单个属性?,xml,powershell,msbuild,powershell-2.0,msbuild-4.0,Xml,Powershell,Msbuild,Powershell 2.0,Msbuild 4.0,我有这样的Msbuild XML文件 <?xml version="1.0" encoding="utf-8"?> <Project xmlns="schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Notifications Include="someone@gmail.com"/> </ItemGroup

我有这样的Msbuild XML文件

<?xml version="1.0" encoding="utf-8"?> 
  <Project xmlns="schemas.microsoft.com/developer/msbuild/2003">
         <ItemGroup>
             <Notifications Include="someone@gmail.com"/>
         </ItemGroup>
    <ItemGroup> 
         <Xcopy Include="..\..\..\Release\UtilitiesAssembly.dll"> 
             <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination> 
         </Xcopy>
         <Xcopy Include="..\..\..\Release\Core.assembly.dll">
             <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination>
         </Xcopy>
         <Xcopy Include="..\..\..\Release\UIAssembly.dll"> 
             <Destination>"..\..\..\Anothercomponent\Folder1</Destination> 
         </Xcopy>
         <Xcopy Include="..\..\..\Release\Core.assembly.dll">
             <Destination>"..\..\..\Anothercomponent\depl\BOM</Destination>
         </Xcopy>
    </Itemgroup>
  </Project>

“.\..\..\Mycomponent\depl\BOM\Folder1
“.\..\..\Mycomponent\depl\BOM\Folder1
“.\..\..\Anothercomponent\Folder1
“.\..\..\Anothercomponent\depl\BOM
实际上,我想像这样对XCopy Itemgroup进行分组

      <Xcopy Include="..\..\..\Release\UtilitiesAssembly.dll;
                    ..\..\..\Release\\Core.assembly.dll;">
      <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination>
     </Xcopy>

     <Xcopy Include="..\..\..\Release\UIAssembly.dll;">
      <Destination>"..\..\..\Anothercomponent\Folder1</Destination>
     </Xcopy>

     <Xcopy Include="..\..\..\Release\Core.assembly.dll">
             <Destination>"..\..\..\Anothercomponent\depl\BOM</Destination>
     </Xcopy>

“.\..\..\Mycomponent\depl\BOM\Folder1
“.\..\..\Anothercomponent\Folder1
“.\..\..\Anothercomponent\depl\BOM

如何使用Powershell或Msbuild或通过其他机制实现此功能这里是一个使用
Group Object
cmdlet实现此功能的示例。它将按
目的地
对xcopy元素进行分组,并将
包含
路径组合成分号分隔的字符串。输出存储在一个新的XML文档中,并使用ved到磁盘。这不会以编程方式更新原始XML。您只需将新的合并XML复制粘贴到原始XML上即可

现在更新我看到了您的整个文件,我看到它有一个默认名称空间,这会导致XPath出现问题

  • 使用
  • 使用命名空间管理器
  • 下面是一个使用名称空间无关xpath的更新示例。此外,为了获得您要查找的缩进,我们需要在XML对象处理之后进行一些文本文件处理

    $xml="Myinput.xml"
    $tempXmlFile = "C:\New.xml"
    
    $outXml = New-Object System.Xml.XmlDocument
    $outXml.AppendChild($outXml.CreateElement("root")) > $null
    
    $x = [xml] (Get-Content $xml)
    $x.SelectNodes("//*[local-name()='Xcopy']") | Group-Object Destination | % {
        $includePaths = ($_.Group | Select-Object -ExpandProperty Include) -join ";"
        $element = $outXml.CreateElement("Xcopy")
        $element2 = $outXml.CreateElement("Destination")
        $element2.InnerText = $_.Name
        $element.AppendChild($element2) > $null
        $element.SetAttribute("Include", $includePaths)
        $outXml.DocumentElement.AppendChild($element) > $null
    }
    $outXml.Save($tempXmlFile)
    
    $data = Get-Content $tempXmlFile | % {
        $search = 'Include="'
        $index = $_.IndexOf('Include="')
        if ($index -gt 0) { 
            $spaces = ( ' ' * ($index + $search.length) ) 
        }
        $_ -replace ';', ";`n${spaces}"
    }
    $data | Set-Content $tempXmlFile
    & notepad $tempXmlFile
    
    创建输出:

    <root>
      <Xcopy Include="..\..\..\Release\UtilitiesAssembly.dll
                      ..\..\..\Release\Core.assembly.dll">
        <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination>
      </Xcopy>
      <Xcopy Include="..\..\..\Release\UIAssembly.dll">
        <Destination>"..\..\..\Anothercomponent\Folder1</Destination>
      </Xcopy>
      <Xcopy Include="..\..\..\Release\Core.assembly.dll">
        <Destination>"..\..\..\Anothercomponent\depl\BOM</Destination>
      </Xcopy>
    </root>
    
    
    “.\..\..\Mycomponent\depl\BOM\Folder1
    “.\..\..\Anothercomponent\Folder1
    “.\..\..\Anothercomponent\depl\BOM
    
    下面是一个如何使用
    组对象
    cmdlet执行此操作的示例。它将根据
    Destination
    对xcopy元素进行分组,并将
    Include
    路径组合成分号分隔的字符串。输出存储在新的XML文档中并保存到磁盘。这不会以编程方式更新原始文件。您只需将新的合并XML复制粘贴到原始XML上即可

    更新现在我看到了您的整个文件,我看到它有一个默认名称空间,这会导致XPath出现问题。有两种方法可以解决这个问题

  • 使用
  • 使用命名空间管理器
  • 下面是一个使用名称空间无关xpath的更新示例。此外,为了获得您正在寻找的缩进,我们需要在XML对象处理之后进行一些文本文件处理

    $xml="Myinput.xml"
    $tempXmlFile = "C:\New.xml"
    
    $outXml = New-Object System.Xml.XmlDocument
    $outXml.AppendChild($outXml.CreateElement("root")) > $null
    
    $x = [xml] (Get-Content $xml)
    $x.SelectNodes("//*[local-name()='Xcopy']") | Group-Object Destination | % {
        $includePaths = ($_.Group | Select-Object -ExpandProperty Include) -join ";"
        $element = $outXml.CreateElement("Xcopy")
        $element2 = $outXml.CreateElement("Destination")
        $element2.InnerText = $_.Name
        $element.AppendChild($element2) > $null
        $element.SetAttribute("Include", $includePaths)
        $outXml.DocumentElement.AppendChild($element) > $null
    }
    $outXml.Save($tempXmlFile)
    
    $data = Get-Content $tempXmlFile | % {
        $search = 'Include="'
        $index = $_.IndexOf('Include="')
        if ($index -gt 0) { 
            $spaces = ( ' ' * ($index + $search.length) ) 
        }
        $_ -replace ';', ";`n${spaces}"
    }
    $data | Set-Content $tempXmlFile
    & notepad $tempXmlFile
    
    创建输出:

    <root>
      <Xcopy Include="..\..\..\Release\UtilitiesAssembly.dll
                      ..\..\..\Release\Core.assembly.dll">
        <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination>
      </Xcopy>
      <Xcopy Include="..\..\..\Release\UIAssembly.dll">
        <Destination>"..\..\..\Anothercomponent\Folder1</Destination>
      </Xcopy>
      <Xcopy Include="..\..\..\Release\Core.assembly.dll">
        <Destination>"..\..\..\Anothercomponent\depl\BOM</Destination>
      </Xcopy>
    </root>
    
    
    “.\..\..\Mycomponent\depl\BOM\Folder1
    “.\..\..\Anothercomponent\Folder1
    “.\..\..\Anothercomponent\depl\BOM
    
    从MSBuild 3.5开始,您可以使用

    
    “.\..\..\Mycomponent\depl\BOM\Folder1
    “.\..\..\Anothercomponent\Folder1
    
    从MSBuild 3.5开始,您可以使用

    
    “.\..\..\Mycomponent\depl\BOM\Folder1
    “.\..\..\Anothercomponent\Folder1
    
    我收到以下问题。无法将值“E:\Powershellscripts\Comp1.Targets”转换为类型“System.Xml.XmlDocument”。错误:“根级别的数据无效。第1行,位置1。“我的输入文件如下所示”“..\..\..\Mycomponent\depl\BOM\Folder1”“。\..\..\Mycomponent\depl\BOM\Folder1如果将Get content$xml替换为$xml,我会遇到相同的错误。所以我编辑了答案。谢谢你,伙计。@Samselvaprabu Woops我把你的源XML放在一个here字符串中进行了一点不同的测试。我将我的更新复制到答案中,没有为您重新调整。谢谢。我收到了以下问题,伙计。无法将值“E:\Powershellscripts\Comp1.Targets”转换为类型“System.Xml.XmlDocument”。错误:“根级别的数据无效。第1行,位置1。”我的输入文件如下“…\…\Mycomponent\depl\BOM\Folder1”“..\..\..\Mycomponent\depl\BOM\Folder1如果将Get content$xml替换为$xml,则我会遇到与我遇到的相同的错误。所以我编辑了答案。谢谢你,伙计。@Samselvaprabu Woops我把你的源XML放在一个here字符串中进行了一点不同的测试。我将我的更新复制到答案中,没有为您重新调整。谢谢。我认为Itemdefinitiongroup如果能为所有人提供通用的元数据,就可以工作了。这是一个有用的信息。我进一步澄清了我的问题。它对这种情况有效吗?我认为Itemdefinitiongroup可以工作,如果它对所有人都有公共元数据的话。这是一个有用的信息。我进一步澄清了我的问题。这个案子行得通吗?