简体   繁体   中英

Updating XML element and attribute value using Powershell

Here is the XML I am working with. This is in a sqlproj file and would like to update the value '..\cwdb.dacpac' in the Include attribute of ArtifactReference and the node element HintPath to a new value.

<ItemGroup>
    <ArtifactReference Include="$(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\AzureV12\SqlSchemas\master.dacpac">
      <HintPath>$(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\AzureV12\SqlSchemas\master.dacpac</HintPath>
      <SuppressMissingDependenciesErrors>True</SuppressMissingDependenciesErrors>
      <DatabaseVariableLiteralValue>master</DatabaseVariableLiteralValue>
    </ArtifactReference>
    <ArtifactReference Include="..\cwdb.dacpac">
      <HintPath>..\cwdb.dacpac</HintPath>
      <SuppressMissingDependenciesErrors>True</SuppressMissingDependenciesErrors>
      <DatabaseVariableLiteralValue>cwdb</DatabaseVariableLiteralValue>
    </ArtifactReference>
  </ItemGroup>

Parts of the code below is based on this blog https://blogs.like10.com/2014/06/17/versioning-your-sql-server-database-using-team-build-and-release-management/ , however it does not update the values. In the call to function Set-XMlElementsTextValue, the element path HintPath is passed to update its value. How do I change the Include attribute value as well?

function Get-XmlNode([ xml ]$XmlDocument, [string]$NodePath, [string]$NamespaceURI = “”, [string]$NodeSeparatorCharacter = ‘.’)
{
# If a Namespace URI was not given, use the Xml document’s default namespace.
if ([string]::IsNullOrEmpty($NamespaceURI))
{
$NamespaceURI = $XmlDocument.DocumentElement.NamespaceURI
}
# In order for SelectSingleNode() to actually work, we need to use the fully qualified node path along with an Xml Namespace Manager, so set them up.
$xmlNsManager = New-Object System.Xml.XmlNamespaceManager($XmlDocument.NameTable)
$xmlNsManager.AddNamespace(“ns”, $NamespaceURI)
$fullyQualifiedNodePath = “/ns:$($NodePath.Replace($($NodeSeparatorCharacter), ‘/ns:’))”
$node = $XmlDocument.SelectSingleNode($fullyQualifiedNodePath, $xmlNsManager)

return $node
}
function Set-XMlElementsTextValue([ xml ]$XmlDocument, [string]$ElementPath, [string]$TextValue)
{
    $node = Get-XmlNode -XmlDocument $XmlDocument -NodePath $ElementPath
    # If the node exists, update its value.
    if ($node)
    {
         $node.InnerText = $TextValue
    }
}

$path = "C:\Shared\DACPAC\"
$NewText = $path + "cwdb.dacpac"
$files = gci $env:BUILD_SOURCESDIRECTORY -recurse |
         ?{ $_.Extension -eq ".sqlproj" } |
         foreach { gci -Path $_.FullName -Recurse -include *.sqlproj }

if($files)
{
        foreach ($file in $files) {
            [xml]$fileContent = Get-Content($file)
             attrib $file -r
            #Read in the file contents, update the element's value, and save the file.
             Set-XMlElementsTextValue -XmlDocument $fileContent -ElementPath "Project.ItemGroup.ArtifactReference.HintPath" -TextValue $NewText
            $fileContent.Save($file)
           }

}
else
{
        Write-Output "Found no *.sqlproj files."
}

I updated my code and got rid of the functions and included the namespace in the main code. This may not be the most elegant solution but here is the revised code that worked:

if($files)
{
        foreach ($file in $files) {
            [xml]$fileContent = Get-Content($file)
             attrib $file -r

            $XPath = "/ns:Project/ns:ItemGroup/ns:ArtifactReference[@Include='..\cwdb.dacpac']"          
            $namespace = $fileContent.DocumentElement.NamespaceURI
            $ns = New-Object System.Xml.XmlNamespaceManager($fileContent.NameTable)
            $ns.AddNamespace("ns", $namespace)
            $artifacts = $fileContent.SelectSingleNode($XPath, $ns)
            # update HintPath node value
            $artifacts.SelectSingleNode("./ns:HintPath", $ns)."#text" = $NewText
            Foreach ($artifact in $artifacts) 
            {   # update Include attribute value
                $artifact.SetAttribute("Include", $NewText) 
            }

            $fileContent.Save($file)

            Write-Output "$file.FullName = update applied"
            }


}
else
{
        Write-Output "Found no *.sqlproj files."
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM