├── Build.PSake.ps1 ├── ChangeLog.md ├── Examples ├── Example01.ps1 ├── Example02.ps1 ├── Example03.ps1 └── Example04.ps1 ├── LICENSE ├── README.md ├── Src ├── Private │ ├── Assert-XmlExFile.ps1 │ ├── Assert-XmlExXPath.ps1 │ └── Resolve-XmlExNamespace.ps1 └── Public │ ├── Add-XmlExAttribute.ps1 │ ├── Add-XmlExComment.ps1 │ ├── Add-XmlExElement.ps1 │ ├── Add-XmlExNamespace.ps1 │ ├── Add-XmlExText.ps1 │ ├── Format-XmlEx.ps1 │ ├── New-XmlExDocument.ps1 │ ├── Set-XmlExConfigKeyValue.ps1 │ └── Set-XmlExDeclaration.ps1 ├── Tests ├── Linting │ ├── FileEncoding.Tests.ps1 │ ├── PSScriptAnalyzer.Tests.ps1 │ └── Style.Tests.ps1 └── Unit │ └── Src │ └── Public │ ├── Add-XmlExAttribute.Tests.ps1 │ ├── Add-XmlExComment.Tests.ps1 │ ├── Add-XmlExElement.Tests.ps1 │ ├── Add-XmlExNamespace.Tests.ps1 │ ├── Add-XmlExText.Tests.ps1 │ ├── New-XmlExDocument.Tests.ps1 │ └── Set-XmlExDeclaration.Tests.ps1 ├── VE_Certificate_2019.pfx.enc ├── XmlEx.nuspec ├── XmlEx.psd1 ├── XmlEx.psm1 ├── appveyor.yml ├── en-US └── XmlEx.Resources.psd1 └── xml-tool-icon-53260.png /Build.PSake.ps1: -------------------------------------------------------------------------------- 1 | #requires -Version 5; 2 | #requires -Modules VirtualEngine.Build; 3 | 4 | $psake.use_exit_on_error = $true; 5 | 6 | Properties { 7 | $moduleName = (Get-Item $PSScriptRoot\*.psd1)[0].BaseName; 8 | $basePath = $psake.build_script_dir; 9 | $buildDir = 'Release'; 10 | $buildPath = (Join-Path -Path $basePath -ChildPath $buildDir); 11 | $releasePath = (Join-Path -Path $buildPath -ChildPath $moduleName); 12 | $thumbprint = '3DACD0F2D1E60EB33EC774B9CFC89A4BEE9037AF'; 13 | $timeStampServer = 'http://timestamp.verisign.com/scripts/timestamp.dll'; 14 | $exclude = @( 15 | '.git*', 16 | '.vscode', 17 | 'Release', 18 | 'Tests', 19 | 'Build.PSake.ps1', 20 | '*.png', 21 | '*.md', 22 | '*.enc', 23 | 'TestResults.xml', 24 | 'appveyor.yml', 25 | 'appveyor-tools' 26 | 'PScribo Test Doc.*', 27 | 'PScriboExample.*', 28 | 'TestResults.xml', 29 | 'Docs', 30 | '_DSCResources' 31 | ); 32 | $signExclude = @('Examples','en-US'); 33 | } 34 | 35 | 36 | # Synopsis: Initialises build variables 37 | Task Init { 38 | 39 | # Properties are not available in the script scope. 40 | Set-Variable manifest -Value (Get-ModuleManifest) -Scope Script; 41 | Set-Variable version -Value $manifest.Version -Scope Script; 42 | Write-Host (" Building module '{0}'." -f $manifest.Name) -ForegroundColor Yellow; 43 | Write-Host (" Building version '{0}'." -f $version) -ForegroundColor Yellow; 44 | } #end task Init 45 | 46 | # Synopsis: Cleans the release directory 47 | Task Clean -Depends Init { 48 | 49 | Write-Host (' Cleaning release directory "{0}".' -f $buildPath) -ForegroundColor Yellow; 50 | if (Test-Path -Path $buildPath) { 51 | Remove-Item -Path $buildPath -Include * -Recurse -Force; 52 | } 53 | [ref] $null = New-Item -Path $buildPath -ItemType Directory -Force; 54 | [ref] $null = New-Item -Path $releasePath -ItemType Directory -Force; 55 | } #end task Clean 56 | 57 | # Synopsis: Invokes Pester tests 58 | Task Test -Depends Init { 59 | 60 | $invokePesterParams = @{ 61 | Path = "$basePath\Tests"; 62 | OutputFile = "$basePath\TestResults.xml"; 63 | OutputFormat = 'NUnitXml'; 64 | Strict = $true; 65 | PassThru = $true; 66 | Verbose = $false; 67 | } 68 | $testResult = Invoke-Pester @invokePesterParams; 69 | if ($testResult.FailedCount -gt 0) { 70 | Write-Error ('Failed "{0}" unit tests.' -f $testResult.FailedCount); 71 | } 72 | } 73 | 74 | # Synopsis: Copies release files to the release directory 75 | Task Deploy -Depends Clean { 76 | 77 | Get-ChildItem -Path $basePath -Exclude $exclude | ForEach-Object { 78 | Write-Host (' Copying {0}' -f $PSItem.FullName) -ForegroundColor Yellow; 79 | Copy-Item -Path $PSItem -Destination $releasePath -Recurse; 80 | } 81 | } #end 82 | 83 | # Synopsis: Signs files in release directory 84 | Task Sign -Depends Deploy { 85 | 86 | if (-not (Get-ChildItem -Path Cert:\CurrentUser\My | Where-Object Thumbprint -eq $thumbprint)) { 87 | ## Decrypt and import code signing cert 88 | .\appveyor-tools\secure-file.exe -decrypt .\VE_Certificate_2019.pfx.enc -secret $env:certificate_secret 89 | $certificatePassword = ConvertTo-SecureString -String $env:certificate_secret -AsPlainText -Force 90 | Import-PfxCertificate -FilePath .\VE_Certificate_2019.pfx -CertStoreLocation 'Cert:\CurrentUser\My' -Password $certificatePassword 91 | } 92 | 93 | Get-ChildItem -Path $releasePath -Exclude $signExclude | ForEach-Object { 94 | if ($PSItem -is [System.IO.DirectoryInfo]) { 95 | Get-ChildItem -Path $PSItem.FullName -Include *.ps* -Recurse | ForEach-Object { 96 | Write-Host (' Signing {0}' -f $PSItem.FullName) -ForegroundColor Yellow -NoNewline; 97 | $signResult = Set-ScriptSignature -Path $PSItem.FullName -Thumbprint $thumbprint -TimeStampServer $timeStampServer -ErrorAction Stop; 98 | Write-Host (' {0}.' -f $signResult.Status) -ForegroundColor Green; 99 | } 100 | 101 | } 102 | elseif ($PSItem.Name -like '*.ps*') { 103 | Write-Host (' Signing {0}' -f $PSItem.FullName) -ForegroundColor Yellow -NoNewline; 104 | $signResult = Set-ScriptSignature -Path $PSItem.FullName -Thumbprint $thumbprint -TimeStampServer $timeStampServer -ErrorAction Stop; 105 | Write-Host (' {0}.' -f $signResult.Status) -ForegroundColor Green; 106 | } 107 | } 108 | } 109 | 110 | Task Version -Depends Deploy { 111 | 112 | $nuSpecPath = Join-Path -Path $releasePath -ChildPath "$ModuleName.nuspec" 113 | $nuspec = [System.Xml.XmlDocument] (Get-Content -Path $nuSpecPath -Raw) 114 | $nuspec.Package.MetaData.Version = $version.ToString() 115 | $nuspec.Save($nuSpecPath) 116 | } 117 | 118 | # Synopsis: Publishes release module to PSGallery 119 | Task Publish_PSGallery -Depends Version { 120 | 121 | Publish-Module -Path $releasePath -NuGetApiKey "$env:gallery_api_key" -Verbose 122 | } #end task Publish 123 | 124 | # Synopsis: Creates release module Nuget package 125 | Task Package -Depends Build { 126 | 127 | $targetNuSpecPath = Join-Path -Path $releasePath -ChildPath "$ModuleName.nuspec" 128 | NuGet.exe pack "$targetNuSpecPath" -OutputDirectory "$env:TEMP" 129 | } 130 | 131 | # Synopsis: Publish release module to Dropbox repository 132 | Task Publish_Dropbox -Depends Package { 133 | 134 | $targetNuPkgPath = Join-Path -Path "$env:TEMP" -ChildPath "$ModuleName.$version.nupkg" 135 | $destinationPath = "$env:USERPROFILE\Dropbox\PSRepository" 136 | Copy-Item -Path "$targetNuPkgPath"-Destination $destinationPath -Force -Verbose 137 | } 138 | 139 | # Synopsis: Publish test results to AppVeyor 140 | Task AppVeyor { 141 | 142 | Get-ChildItem -Path "$basePath\*Results*.xml" | Foreach-Object { 143 | $address = 'https://ci.appveyor.com/api/testresults/nunit/{0}' -f $env:APPVEYOR_JOB_ID 144 | $source = $_.FullName 145 | Write-Verbose "UPLOADING TEST FILE: $address $source" -Verbose 146 | (New-Object 'System.Net.WebClient').UploadFile( $address, $source ) 147 | } 148 | } 149 | 150 | Task Default -Depends Init, Clean, Test 151 | Task Build -Depends Default, Deploy, Version, Sign; 152 | Task Publish -Depends Build, Package, Publish_PSGallery 153 | Task Local -Depends Build, Package, Publish_Dropbox 154 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Change Log # 2 | 3 | ## 0.9.5 ## 4 | 5 | * Adds -Prepend switch to XmlComment 6 | 7 | ## 0.9.4 ## 8 | 9 | * Adds -NoPrefix switch parameter to XmlElement and XmlAttribute 10 | * Adds AppVeyor build 11 | * Adds linting tests 12 | -------------------------------------------------------------------------------- /Examples/Example01.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | Import-Module -Name XmlEx -Force; 5 | 6 | $x = XmlDocument { 7 | XmlDeclaration -Encoding 'utf-8' 8 | XmlNamespace -Uri 'http://www.w3.org/XML/1998/namespace' 9 | XmlNamespace -Prefix 'v' -Uri 'http://mycustom/namespace' 10 | XmlNamespace -Prefix 'w' -Uri 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' 11 | XmlElement -Name 'document' -Prefix w { 12 | XmlComment 'My comment' 13 | XmlElement -Name 'body' { 14 | XmlAttribute 'att1' 'value1' -Namespace 'http://www.w3.org/XML/1998/namespace' 15 | XmlAttribute 'att2' 'value2' -Prefix v 16 | XmlText 'My body value' 17 | } 18 | } 19 | } -Verbose 20 | 21 | $x | Format-XmlEx 22 | -------------------------------------------------------------------------------- /Examples/Example02.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | Import-Module -Name XmlEx -Force; 5 | 6 | $x = [System.Xml.XmlDocument] @' 7 | 8 | 9 | 10 | Sub node 11 | '@ 12 | 13 | ## Appending an XmlElement to an exising XmlElement 14 | XmlElement -Name 'appended' -XmlElement $x.document { 15 | XmlElement 'TextNode' { 16 | XmlText 'My text node' 17 | } 18 | } -Verbose 19 | 20 | ## Appending an XmlAttribute to an exising XmlElement 21 | [ref] $null = XmlAttribute -XmlElement $x.document.appended -Name 'myattribute' -Value 'Rubbish!' -verbose 22 | 23 | $x | Format-XmlEx 24 | -------------------------------------------------------------------------------- /Examples/Example03.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | Import-Module -Name XmlEx -Force; 5 | 6 | $x = XmlDocument { 7 | XmlDeclaration 8 | } 9 | 10 | ## Appending an XmlElement to an exising XmlDocument 11 | XmlElement -XmlDocument $x -Name 'rootElement' { 12 | XmlElement 'TextNode' { 13 | XmlText 'My text node' 14 | } 15 | } -Verbose 16 | 17 | $x | Format-XmlEx 18 | -------------------------------------------------------------------------------- /Examples/Example04.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | Import-Module -Name XmlEx -Force; 5 | 6 | $x = XmlDocument { 7 | XmlDeclaration -Encoding 'utf-8' -Standalone 'yes' 8 | XmlElement 'rootElement' 9 | } 10 | 11 | ## Appending an XmlElement to an exising root XmlElement. This is required because 12 | ## $x.rootElement is coerced into [System.String] (only applicable to the root node)? 13 | XmlElement -XmlElement $x.SelectSingleNode('/rootElement') -Name 'subElement' { 14 | XmlElement 'TextNode' { 15 | XmlText 'My text node' 16 | } 17 | } -Verbose 18 | 19 | $x | Format-XmlEx 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Iain Brighton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/od9qahrj937bs1hy?svg=true)](https://ci.appveyor.com/project/iainbrighton/xmlex) 2 | 3 | # XmlEx 4 | 5 | XmlEx (XML EXtensions) provides a PowerShell domain-specific language (DSL) to easily create and update XML documents without having to understand or manipulate the underlying [System.Xml.XmlDocument] objects. XmlEx provides a simple way to: 6 | 7 | * Create and append XML documents in PowerShell 8 | * Manage XML document namespaces and prefixes 9 | 10 | ## Why? 11 | 12 | Traditionally, creating XML documents with PowerShell is slow, cumbersome and error prone. I discovered this whilst developing the [PScribo](http://github.com/iainbrighton/PScribo) plugin to create Word documents. 13 | After my eyes started to bleed looking at the code, I decided there had to be an easier way and `XmlEx` is a result of this! 14 | 15 | Take the following short XML document as an example: 16 | ```XML 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | To generate this in PowerShell code requires something similar to this: 33 | 34 | ```powershell 35 | $xmlDocument = New-Object -TypeName 'System.Xml.XmlDocument'; 36 | $xmlnsMain = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'; 37 | $null = $xmlDocument.AppendChild($xmlDocument.CreateXmlDeclaration('1.0', 'utf-8', 'yes')); 38 | $documentXml = $xmlDocument.AppendChild($xmlDocument.CreateElement('w', 'document', $xmlnsMain)); 39 | $null = $xmlDocument.DocumentElement.SetAttribute('xmlns:xml', 'http://www.w3.org/XML/1998/namespace'); 40 | 41 | $body = $documentXml.AppendChild($xmlDocument.CreateElement('w', 'body', $xmlnsMain)); 42 | 43 | $p = $body.AppendChild($XmlDocument.CreateElement('w', 'p', $xmlnsMain)); 44 | $pPr = $p.AppendChild($XmlDocument.CreateElement('w', 'pPr', $xmlnsMain)); 45 | 46 | $pStyle = $pPr.AppendChild($XmlDocument.CreateElement('w', 'pStyle', $xmlnsMain)); 47 | $null = $pStyle.SetAttribute('val', $xmlnsMain, 'MyStyle'); 48 | 49 | $spacing = $pPr.AppendChild($XmlDocument.CreateElement('w', 'spacing', $xmlnsMain)); 50 | $null = $spacing.SetAttribute('before', $xmlnsMain, 160); 51 | $null = $spacing.SetAttribute('after', $xmlnsMain, 160); 52 | 53 | $r = $p.AppendChild($XmlDocument.CreateElement('w', 'r', $xmlnsMain)); 54 | $t = $r.AppendChild($XmlDocument.CreateElement('w', 't', $xmlnsMain)); 55 | ``` 56 | Using `XmlEx`, this can be simply written as: 57 | 58 | ```powershell 59 | $xmlDocument = XmlDocument { 60 | XmlDeclaration -Encoding 'utf-8' -Standalone 'yes' 61 | XmlNamespace -Prefix 'xml' -Uri 'http://www.w3.org/XML/1998/namespace' 62 | XmlElement document -Prefix 'w' -Namespace 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' { 63 | XmlElement 'body' { 64 | XmlElement 'p' { 65 | XmlElement 'pPr' { 66 | XmlElement 'pStyle' { 67 | XmlAttribute 'val' 'MyStyle' 68 | } 69 | XmlElement 'spacing' { 70 | XmlAttribute 'before' '160' 71 | XmlAttribute 'after' '160' 72 | } 73 | } 74 | XmlElement 'r' { 75 | XmlElement 't' 76 | } 77 | } 78 | } 79 | } 80 | } 81 | ``` 82 | 83 | ## Quick start 84 | 85 | * Install XmlEx module from the [PowerShell Gallery](https://powershellgallery.com): 86 | 87 | ```powershell 88 | Install-Module -Name XmlEx -Scope CurrentUser 89 | Import-Module XmlEx 90 | ``` 91 | 92 | There are examples in module's \Examples folder. 93 | -------------------------------------------------------------------------------- /Src/Private/Assert-XmlExFile.ps1: -------------------------------------------------------------------------------- 1 | function Assert-XmlExFilePath { 2 | <# 3 | .SYNOPSIS 4 | Ensures the target Xml document XPath does or doesn't exist. 5 | 6 | .DESCRIPTION 7 | Ensures that the specified Xml document XPath location does or does not exist. If the path does not exist, the 8 | cmdlet will create the Xml document XPath. 9 | #> 10 | [CmdletBinding(SupportsShouldProcess)] 11 | param ( 12 | # Specifies a path to the Xml document. 13 | [Parameter(Mandatory, ValueFromPipelineByPropertyName)] 14 | [System.String] $Path, 15 | 16 | ## Specifies whether the Xml document should or should not exist. 17 | [Parameter(ValueFromPipelineByPropertyName)] 18 | [ValidateSet('Present','Absent')] 19 | [System.String] $Ensure = 'Present' 20 | ) 21 | process { 22 | 23 | if ($Ensure -eq 'Present') { 24 | 25 | if (Test-Path -Path $Path -PathType Leaf) { 26 | 27 | $xmlDocument = New-Object -TypeName System.Xml.XmlDocument; 28 | $xmlDocument.Load($Path); 29 | } 30 | else { 31 | 32 | Write-Verbose -Message ("Xml document '{0}' does not exist. Attempting to create.." -f $Path); 33 | 34 | $parentPath = Split-Path -Path $Path -Parent 35 | if (-not (Test-Path -Path $parentPath -PathType Container)) { 36 | 37 | Write-Verbose -Message ("Parent directory '{0}' does not exist. Attempting to create.." -f $parentPath); 38 | $newItemParams = @{ 39 | Path = Split-Path -Path $parentPath -Parent; 40 | Name = Split-Path -Path $parentPath -Leaf; 41 | ItemType = 'Directory'; 42 | Force = $true;; 43 | } 44 | [ref] $null = New-Item @newItemParams; 45 | } 46 | 47 | $xmlDocument = New-XmlExDocument -Verbose:$false { 48 | 49 | ## Ensure we have a declaration 50 | Set-XmlExDeclaration 51 | } 52 | } 53 | 54 | return $xmlDocument; 55 | 56 | } 57 | elseif ($Ensure -eq 'Absent') { 58 | 59 | if (Test-Path -Path $Path -PathType Leaf) { 60 | 61 | Write-Verbose -Message ("Xml document '{0}' exists. Attempting to remove.." -f $Path); 62 | Remove-Item -Path $Path -Force; 63 | 64 | } 65 | } 66 | 67 | } #end process 68 | } #end function 69 | -------------------------------------------------------------------------------- /Src/Private/Assert-XmlExXPath.ps1: -------------------------------------------------------------------------------- 1 | function Assert-XmlExXPath { 2 | <# 3 | .SYNOPSIS 4 | Ensures that the specified XPath and element/attribute is present in an Xml document. 5 | #> 6 | [CmdletBinding(SupportsShouldProcess)] 7 | param ( 8 | ## Specifies the Xml document to add the Xml element/attribute to. 9 | [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] 10 | [System.Xml.XmlDocument] $XmlDocument, 11 | 12 | ## Specifies the XPath location of the parent Xml element within the document to update. 13 | [Parameter(Mandatory, ValueFromPipelineByPropertyName)] 14 | [System.String] $XPath, 15 | 16 | ## Specifies the name of the Xml element or Xml attribute to update. 17 | [Parameter(Mandatory, ValueFromPipelineByPropertyName)] 18 | [System.String] $Name, 19 | 20 | ## Specifies the value of the Xml element or Xml attribute to update. 21 | [Parameter(ValueFromPipelineByPropertyName)] 22 | [System.String] $Value, 23 | 24 | ## Specifies the target is an attribute. Defaults to an element. 25 | [Parameter(ValueFromPipelineByPropertyName)] 26 | [System.Management.Automation.SwitchParameter] $IsAttribute, 27 | 28 | ## Specifies the target Xml element should be created if it does not exist. 29 | [Parameter(ValueFromPipelineByPropertyName)] 30 | [System.Management.Automation.SwitchParameter] $Force 31 | ) 32 | begin { 33 | 34 | $XPath = $XPath.Trim('/'); 35 | if (-not $IsAttribute) { 36 | 37 | ## We have an element so ensure it's added to the path.. 38 | $XPath = '{0}/{1}' -f $XPath, $Name; 39 | } 40 | 41 | } 42 | process { 43 | 44 | ## Ensure all the path elements exist. 45 | foreach ($xpathNode in $XPath.Split('/')) { 46 | 47 | $currentPath = '{0}/{1}' -f $currentPath, $xpathNode; 48 | $xmlNode = $xmlDocument.SelectSingleNode($currentPath); 49 | 50 | if ($null -eq $xmlNode) { 51 | 52 | ## Create the element 53 | $verboseMessage = $localized.AppendingXmlElementPath -f $currentPath; 54 | $warningConfirmationMessage = $localized.ShouldProcessWarning; 55 | $warningDescriptionMessage = $localized.ShouldProcessOperationWarning -f 'Append', $xpathNode; 56 | if ($Force -or ($PSCmdlet.ShouldProcess($verboseMessage, $warningConfirmationMessage, $warningDescriptionMessage))) { 57 | 58 | $xmlNode = $currentNode.AppendChild($XmlDocument.CreateElement($xpathNode)); 59 | } 60 | } 61 | 62 | $currentNode = $xmlNode; 63 | 64 | } 65 | 66 | if ($IsAttribute) { 67 | 68 | ## Create the element 69 | $attributePath = '{0}[@{1}]' -f $currentPath, $xpathNode; 70 | $verboseMessage = $localized.AppendingXmlAttributePath -f $attributePath; 71 | $warningConfirmationMessage = $localized.ShouldProcessWarning; 72 | $warningDescriptionMessage = $localized.ShouldProcessOperationWarning -f 'Append', $attributePath; 73 | if ($Force -or ($PSCmdlet.ShouldProcess($verboseMessage, $warningConfirmationMessage, $warningDescriptionMessage))) { 74 | 75 | Add-XmlExAttribute -Name $Name -Value $Value -XmlElement $currentNode; 76 | } 77 | 78 | } 79 | else { 80 | 81 | $textNodePath = '{0}[#text]' -f $currentPath; 82 | $verboseMessage = $localized.AppendingXmlTextNodePath -f $textNodePath; 83 | $warningConfirmationMessage = $localized.ShouldProcessWarning; 84 | $warningDescriptionMessage = $localized.ShouldProcessOperationWarning -f 'Append', $textNodePath; 85 | if ($Force -or ($PSCmdlet.ShouldProcess($verboseMessage, $warningConfirmationMessage, $warningDescriptionMessage))) { 86 | 87 | if ($currentNode.'#text') { 88 | 89 | # Add-XmlExText appends the value to the text node?! 90 | $currentNode.'#text' = $Value; 91 | 92 | } 93 | else { 94 | 95 | Add-XmlExText -XmlElement $currentNode -Text $Value; 96 | 97 | } 98 | 99 | } 100 | 101 | } 102 | 103 | } #end process 104 | } #end function 105 | -------------------------------------------------------------------------------- /Src/Private/Resolve-XmlExNamespace.ps1: -------------------------------------------------------------------------------- 1 | function Resolve-XmlExNamespace { 2 | <# 3 | .SYNOPSIS 4 | Resolves supplied prefix/namespace from the XmlEx namespace manager. 5 | .DESCRIPTION 6 | The Resolve-XmlExNamespace method resolves defined Xml namespaces 7 | within the XmlEx document. 8 | 9 | Namespaces can be resolved by prefix or Uri, with Prefix being 10 | checked first. If no match is found, the namespace Uri is checked. 11 | If the namespace is not defined, an entry is not created in the XmlEx 12 | namespace manager, but object is still returned. 13 | #> 14 | [CmdletBinding()] 15 | [OutputType([System.Management.Automation.PSCustomObject])] 16 | param ( 17 | ## Namespace prefix 18 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'Namespace')] 19 | [System.String] $Prefix, 20 | 21 | ## Namespace Uri 22 | [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'Namespace')] 23 | [System.String] $Namespace, 24 | 25 | ## Catch-all to enable splatting 26 | [Parameter(ValueFromRemainingArguments)] 27 | [System.Object[]] $RemainingArguments 28 | ) 29 | process { 30 | 31 | if ($PSBoundParameters.ContainsKey('Prefix')) { 32 | ## Try matching on Prefix first 33 | foreach ($namespaceKey in $_xmlExDocumentNamespaces.Keys) { 34 | 35 | $ns = $_xmlExDocumentNamespaces[$namespaceKey]; 36 | if ($ns.Prefix -eq $Prefix) { 37 | $xmlNamespace = $ns; 38 | break; 39 | } 40 | } 41 | } 42 | 43 | ## If we have no match, try matching on Uri 44 | if (($PSBoundParameters.ContainsKey('Namespace')) -and ($null -eq $xmlNamespace)) { 45 | 46 | foreach ($namespaceKey in $_xmlExDocumentNamespaces.Keys) { 47 | 48 | $ns = $_xmlExDocumentNamespaces[$namespaceKey]; 49 | if ($ns.Uri -eq $Namespace) { 50 | $xmlNamespace = $ns; 51 | break; 52 | } 53 | } 54 | } 55 | 56 | if (($null -ne $xmlNamespace) -and ([System.String]::IsNullOrEmpty($xmlNamespace.Prefix))) { 57 | 58 | <# 59 | If we have a defined default namespace, remove the explicit namespace Uri, otherwise we'll end up with 60 | somthing like: d2p1:att2="value2" xmlns:d2p1="http://www.w3.org/XML/1998/namespace" when we add the 61 | object with a namespace. 62 | 63 | We don't want to modify the existing object, so create a new one 64 | #> 65 | $xmlNamespace = [PSCustomObject] @{ 66 | Prefix = $null; 67 | Uri = $null; 68 | DisplayName = 'xmlns="{0}"' -f $Namespace; 69 | } 70 | } 71 | elseif ($null -eq $xmlNamespace) { 72 | 73 | ## We have no matching defined namespace, so create an namespace custom object 74 | 75 | $xmlNamespace = [PSCustomObject] @{ 76 | Prefix = $Prefix; 77 | Uri = $Namespace; 78 | DisplayName = 'xmlns="{0}"' -f $Namespace; 79 | } 80 | 81 | if ($PSBoundParameters.ContainsKey('Prefix')) { 82 | $XmlNamespace.DisplayName = 'xmlns:{0}="{1}"' -f $Prefix, $Namespace; 83 | } 84 | } 85 | 86 | return $xmlNamespace; 87 | 88 | } #end process 89 | } #end function Resolve-XmlExNamespace 90 | -------------------------------------------------------------------------------- /Src/Public/Add-XmlExAttribute.ps1: -------------------------------------------------------------------------------- 1 | function Add-XmlExAttribute { 2 | <# 3 | .SYNOPSIS 4 | Adds a XmlAttribute 5 | .DESCRIPTION 6 | The Add-XmlExAttribute cmdlet adds a System.Xml.XmlAttribute to a XmlEx 7 | document or existing System.Xml.XmlDocument object. 8 | #> 9 | [CmdletBinding(DefaultParameterSetName = 'XmlEx')] 10 | [Alias('XmlAttribute')] 11 | [OutputType([System.Xml.XmlAttribute])] 12 | param ( 13 | ## Xml attribute name to add 14 | [Parameter(Mandatory, Position = 0, ParameterSetName = 'XmlEx')] 15 | [Parameter(Mandatory, Position = 0, ParameterSetName = 'XmlExNoPrefix')] 16 | [Parameter(Mandatory, Position = 0, ParameterSetName = 'XmlElement')] 17 | [Parameter(Mandatory, Position = 0, ParameterSetName = 'XmlElementNoPrefix')] 18 | [ValidateNotNullOrEmpty()] 19 | [System.String] $Name, 20 | 21 | ## Xml attribute value to add 22 | [Parameter(Mandatory, Position = 1, ParameterSetName = 'XmlEx')] 23 | [Parameter(Mandatory, Position = 1, ParameterSetName = 'XmlExNoPrefix')] 24 | [Parameter(Mandatory, Position = 1, ParameterSetName = 'XmlElement')] 25 | [Parameter(Mandatory, Position = 1, ParameterSetName = 'XmlElementNoPrefix')] 26 | [ValidateNotNull()] 27 | [System.Object] $Value, 28 | 29 | ## Xml namespace assigned to the attribute 30 | [Parameter(ParameterSetName = 'XmlEx')] 31 | [Parameter(ParameterSetName = 'XmlElement')] 32 | [ValidateNotNullOrEmpty()] 33 | [System.Uri] $Namespace, 34 | 35 | ## Xml namespace prefixed assigned to the element 36 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlEx')] 37 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElement')] 38 | [ValidateNotNullOrEmpty()] 39 | [System.String] $Prefix, 40 | 41 | ## Existing Xml element to add the attribute to 42 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElement')] 43 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElementNoPrefix')] 44 | [ValidateNotNull()] 45 | [System.Xml.XmlElement] $XmlElement, 46 | 47 | ## Returns the create XmlAttrbiute object to the pipeline. By default, this cmdlet does not generate any output. 48 | [Parameter(ValueFromPipelineByPropertyName)] 49 | [System.Management.Automation.SwitchParameter] $PassThru, 50 | 51 | ## Suppresses attribute prefix 52 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlExNoPrefix')] 53 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElementNoPrefix')] 54 | [System.Management.Automation.SwitchParameter] $NoPrefix 55 | ) 56 | begin { 57 | 58 | if ($PSCmdlet.ParameterSetName -eq 'XmlElement') { 59 | 60 | Write-Debug ("Inferring document from element '{0}'," -f $Name); 61 | $_xmlExCurrentDocument = $XmlElement.OwnerDocument; 62 | $_xmlExCurrentElement = $XmlElement; 63 | } 64 | 65 | if (($PSBoundParameters.ContainsKey('Namespace')) -or 66 | ($PSBoundParameters.ContainsKey('Prefix'))) { 67 | 68 | [ref] $null = $PSBoundParameters.Remove('Name'); 69 | $_xmlExCurrentNamespace = Resolve-XmlExNamespace @PSBoundParameters; 70 | } 71 | 72 | if ($null -eq $_xmlExCurrentDocument) { 73 | throw ($localized.XmlExDocumentNotFoundError); 74 | } 75 | 76 | if ($null -eq $_xmlExCurrentElement) { 77 | throw ($localized.XmlExElementNotFoundError); 78 | } 79 | 80 | } #end begin 81 | process { 82 | 83 | $attributeDisplayName = $Name; 84 | if (-not [System.String]::IsNullOrEmpty($_xmlExCurrentNamespace.Prefix)) { 85 | $attributeDisplayName = '{0}:{1}' -f $_xmlExCurrentNamespace.Prefix, $Name; 86 | } 87 | 88 | $_xmlExCurrentElementIndent ++; 89 | $padding = ''.PadRight($_xmlExCurrentElementIndent); 90 | $paddedMessage = '{0}{1}' -f $padding, ($localized.AddingAttribute -f $attributeDisplayName, $_xmlExCurrentElement.LocalName); 91 | Write-Verbose -Message $paddedMessage; 92 | 93 | if ($NoPrefix) { 94 | $xmlAttribute = $_xmlExCurrentDocument.CreateAttribute($Name); 95 | } 96 | else { 97 | $xmlAttribute = $_xmlExCurrentDocument.CreateAttribute($_xmlExCurrentNamespace.Prefix, $Name, $_xmlExCurrentNamespace.Uri); 98 | } 99 | $xmlAttribute.InnerText = $Value; 100 | 101 | if ($_xmlExCurrentElement -is [System.Xml.XmlDocument]) { 102 | 103 | if ($null -eq $_xmlExCurrentDocument.DocumentElement) { 104 | throw ($localized.XmlExDocumentMissingXmlElementError); 105 | } 106 | 107 | [ref] $null = $_xmlExCurrentDocument.DocumentElement.SetAttributeNode($xmlAttribute); 108 | } 109 | else { 110 | 111 | [ref] $null = $_xmlExCurrentElement.SetAttributeNode($xmlAttribute); 112 | } 113 | 114 | if ($PassThru) { 115 | 116 | Write-Output -InputObject $xmlAttribute; 117 | } 118 | 119 | } #end process 120 | } #end function XmlAttribute 121 | -------------------------------------------------------------------------------- /Src/Public/Add-XmlExComment.ps1: -------------------------------------------------------------------------------- 1 | function Add-XmlExComment { 2 | <# 3 | .SYNOPSIS 4 | Adds a XmlComment 5 | .DESCRIPTION 6 | The Add-XmlExComment cmdlet adds a System.Xml.XmlComment to a XmlEx 7 | document or existing System.Xml.XmlDocument object. 8 | #> 9 | [CmdletBinding(DefaultParameterSetName = 'XmlEx')] 10 | [Alias('XmlComment')] 11 | [OutputType([System.Xml.XmlComment])] 12 | param ( 13 | ## Comment to insert into the Xml document 14 | [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'XmlEx')] 15 | [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'XmlElement')] 16 | [ValidateNotNullOrEmpty()] 17 | [System.String] $Comment, 18 | 19 | ## Existing Xml element to add the comment to 20 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElement')] 21 | [ValidateNotNull()] 22 | [System.Xml.XmlElement] $XmlElement, 23 | 24 | ## Adds the comment as the first child of the specified element. 25 | [Parameter(ValueFromPipelineByPropertyName)] 26 | [System.Management.Automation.SwitchParameter] $Prepend, 27 | 28 | ## Returns the XmlComment to the pipeline. By default, this cmdlet does not generate any output. 29 | [Parameter(ValueFromPipelineByPropertyName)] 30 | [System.Management.Automation.SwitchParameter] $PassThru 31 | ) 32 | begin { 33 | 34 | if ($PSCmdlet.ParameterSetName -eq 'XmlElement') { 35 | 36 | Write-Debug ("Inferring document from element '{0}'," -f $Name); 37 | $_xmlExCurrentDocument = $XmlElement.OwnerDocument; 38 | $_xmlExCurrentElement = $XmlElement; 39 | } 40 | 41 | if ($null -eq $_xmlExCurrentDocument) { 42 | throw ($localized.XmlExDocumentNotFoundError); 43 | } 44 | 45 | if ($null -eq $_xmlExCurrentElement) { 46 | throw ($localized.XmlExElementNotFoundError); 47 | } 48 | 49 | } #end begin 50 | process { 51 | 52 | $padding = ''; 53 | if ($_xmlExCurrentElementIndent) { 54 | $padding = ''.PadRight($_xmlExCurrentElementIndent +1); 55 | } 56 | $paddedMessage = '{0}{1}' -f $padding, ($localized.AddingComment -f $_xmlExCurrentElement.LocalName); 57 | Write-Verbose -Message $paddedMessage; 58 | 59 | $xmlComment = $_xmlExCurrentDocument.CreateComment($Comment); 60 | if ($Prepend) { 61 | [ref] $null = $_xmlExCurrentElement.PrependChild($xmlComment); 62 | } 63 | else { 64 | [ref] $null = $_xmlExCurrentElement.AppendChild($xmlComment); 65 | } 66 | 67 | if ($PassThru) { 68 | Write-Output -InputObject $xmlComment; 69 | } 70 | 71 | } #end process 72 | } #end function XmlComment 73 | -------------------------------------------------------------------------------- /Src/Public/Add-XmlExElement.ps1: -------------------------------------------------------------------------------- 1 | function Add-XmlExElement { 2 | <# 3 | .SYNOPSIS 4 | Adds a XmlElement 5 | .DESCRIPTION 6 | The Add-XmlExElement cmdlet adds a System.Xml.XmlElement to a XmlEx 7 | document or existing System.Xml.XmlDocument object. 8 | #> 9 | [CmdletBinding(DefaultParameterSetName = 'XmlEx')] 10 | [Alias('XmlElement')] 11 | [OutputType([System.Xml.XmlElement])] 12 | param ( 13 | ## Xml element name to add 14 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlEx')] 15 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlElement')] 16 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlDocument')] 17 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlExNoPrefix')] 18 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlElementNoPrefix')] 19 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlDocumentNoPrefix')] 20 | [ValidateNotNullOrEmpty()] 21 | [System.String] $Name, 22 | 23 | ## XmlEx element nested content 24 | [Parameter(ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlElement')] 25 | [Parameter(ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlDocument')] 26 | [Parameter(ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlEx')] 27 | [Parameter(ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlElementNoPrefix')] 28 | [Parameter(ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlDocumentNoPrefix')] 29 | [Parameter(ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlExNoPrefix')] 30 | [ValidateNotNull()] 31 | [System.Management.Automation.ScriptBlock] $ScriptBlock, 32 | 33 | ## Xml namespace assigned to the element 34 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlEx')] 35 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElement')] 36 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocument')] 37 | [ValidateNotNullOrEmpty()] 38 | [System.Uri] $Namespace, 39 | 40 | ## Xml namespace prefixed assigned to the element 41 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlEx')] 42 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElement')] 43 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocument')] 44 | [ValidateNotNullOrEmpty()] 45 | [System.String] $Prefix, 46 | 47 | ## Existing Xml element to add the element to 48 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElement')] 49 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElementNoPrefix')] 50 | [ValidateNotNull()] 51 | [System.Xml.XmlElement] $XmlElement, 52 | 53 | ## Existing Xml document containing the Xml element to add to 54 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocument')] 55 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocumentPrefix')] 56 | [ValidateNotNull()] 57 | [System.Xml.XmlDocument] $XmlDocument, 58 | 59 | ## Returns the created XmlElement object to the pipeline. By default, this cmdlet does not generate any output. 60 | [Parameter(ValueFromPipelineByPropertyName)] 61 | [System.Management.Automation.SwitchParameter] $PassThru, 62 | 63 | ## Suppresses attribute prefix 64 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlExNoPrefix')] 65 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElementNoPrefix')] 66 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocumentPrefix')] 67 | [System.Management.Automation.SwitchParameter] $NoPrefix 68 | ) 69 | begin { 70 | 71 | if ($PSCmdlet.ParameterSetName -eq 'XmlDocument') { 72 | 73 | $_xmlExCurrentDocument = $XmlDocument; 74 | $_xmlExCurrentElement = $XmlDocument; 75 | } 76 | elseif ($PSCmdlet.ParameterSetName -eq 'XmlElement') { 77 | 78 | Write-Debug ("Inferring document from element '{0}'," -f $Name); 79 | $_xmlExCurrentDocument = $XmlElement.OwnerDocument; 80 | $_xmlExCurrentElement = $XmlElement; 81 | } 82 | 83 | if (($PSBoundParameters.ContainsKey('Namespace')) -or 84 | ($PSBoundParameters.ContainsKey('Prefix'))) { 85 | 86 | [ref] $null = $PSBoundParameters.Remove('Name'); 87 | $_xmlExCurrentNamespace = Resolve-XmlExNamespace @PSBoundParameters; 88 | } 89 | 90 | if ($null -eq $_xmlExCurrentDocument) { 91 | throw ($localized.XmlExDocumentNotFoundError); 92 | } 93 | 94 | if ($null -eq $_xmlExCurrentElement) { 95 | throw ($localized.XmlExElementNotFoundError); 96 | } 97 | 98 | } #end begin 99 | process { 100 | 101 | $elementDisplayName = $Name; 102 | if (-not [System.String]::IsNullOrEmpty($_xmlExCurrentNamespace.Prefix)) { 103 | $elementDisplayName = '{0}:{1}' -f $_xmlExCurrentNamespace.Prefix, $Name; 104 | } 105 | 106 | $_xmlExCurrentElementIndent ++; 107 | $padding = ''.PadRight($_xmlExCurrentElementIndent); 108 | $paddedMessage = '{0}{1}' -f $padding, ($localized.AddingElement -f $elementDisplayName, $_xmlExCurrentElement.LocalName); 109 | Write-Verbose -Message $paddedMessage; 110 | 111 | if ($NoPrefix) { 112 | $xmlElement = $_xmlExCurrentDocument.CreateElement($Name); 113 | } 114 | else { 115 | $xmlElement = $_xmlExCurrentDocument.CreateElement($_xmlExCurrentNamespace.Prefix, $Name, $_xmlExCurrentNamespace.Uri); 116 | } 117 | 118 | $_xmlExCurrentElement = $_xmlExCurrentElement.AppendChild($xmlElement); 119 | 120 | if ($PSBoundParameters.ContainsKey('ScriptBlock')) { 121 | [ref] $null = & $ScriptBlock; 122 | } 123 | 124 | if ($PassThru) { 125 | Write-Output -InputObject $_xmlExCurrentElement; 126 | } 127 | 128 | } #end process 129 | } #end function XmlElement 130 | -------------------------------------------------------------------------------- /Src/Public/Add-XmlExNamespace.ps1: -------------------------------------------------------------------------------- 1 | function Add-XmlExNamespace { 2 | <# 3 | .SYNOPSIS 4 | Adds a XmlNamespace 5 | .DESCRIPTION 6 | The Add-XmlExNamespace cmdlet adds a Xml namespace to an existing XmlEx 7 | document namespace manager. 8 | #> 9 | [CmdletBinding(DefaultParameterSetName = 'XmlEx')] 10 | [Alias('XmlNamespace')] 11 | param ( 12 | ## Xml namespace prefix 13 | [Parameter(ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlEx')] 14 | [Parameter(ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlDocument')] 15 | [ValidateNotNullOrEmpty()] 16 | [System.String] $Prefix, 17 | 18 | ## Xml namespace uniform resource identifer 19 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlEx')] 20 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlDocument')] 21 | [ValidateNotNullOrEmpty()] 22 | [System.Uri] $Uri, 23 | 24 | ## Is the default Xml document namespace, automatically applied to all child elements, attributes and comments etc. 25 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlEx')] 26 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocument')] 27 | [ValidateNotNullOrEmpty()] 28 | [System.Management.Automation.SwitchParameter] $IsDefault, 29 | 30 | ## Xml document to add the namespace to 31 | [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocument')] 32 | [ValidateNotNull()] 33 | [System.Xml.XmlDocument] $XmlDocument 34 | ) 35 | process { 36 | 37 | $callingFunction = (Get-PSCallStack)[2]; 38 | if ($callingFunction.FunctionName -ne 'New-XmlExDocument') { 39 | throw ($localized.XmlExInvalidCallOutsideScopeError -f 'XmlNamespace','XmlDocument'); 40 | } 41 | 42 | if ($PSBoundParameters.ContainsKey('Prefix')) { 43 | $xmlNamespaceKey = 'xmlns:{0}' -f $Prefix; 44 | } 45 | else { 46 | $xmlNamespaceKey = 'xmlns'; 47 | } 48 | 49 | $xmlNamespace = [PSCustomObject] @{ 50 | Prefix = $Prefix; 51 | Uri = $Uri.ToString(); 52 | DisplayName = '{0}="{1}"' -f $xmlNamespaceKey, $Uri.ToString(); 53 | }; 54 | Write-Verbose -Message ($localized.SettingDocumentNamespace -f $xmlNamespace.DisplayName); 55 | $_xmlExDocumentNamespaces[$xmlNamespaceKey] = $xmlNamespace; 56 | 57 | if ($IsDefault) { 58 | 59 | Write-Verbose ($localized.SettingDefaultDocumentNamespace -f $xmlNamespace.Uri); 60 | Set-Variable -Name _xmlExCurrentNamespace -Value $xmlNamespace -Scope Script; 61 | 62 | } #end if default 63 | 64 | } #end process 65 | } #end function XmlNamespace 66 | -------------------------------------------------------------------------------- /Src/Public/Add-XmlExText.ps1: -------------------------------------------------------------------------------- 1 | function Add-XmlExText { 2 | <# 3 | .SYNOPSIS 4 | Adds a XmlText node. 5 | .DESCRIPTION 6 | The Add-XmlExText cmdlet adds a System.Xml.XmlTextNode to a XmlEx 7 | document or existing System.Xml.XmlDocument object. 8 | #> 9 | [CmdletBinding(DefaultParameterSetName = 'XmlEx')] 10 | [Alias('XmlText')] 11 | [OutputType([System.Xml.XmlText])] 12 | param ( 13 | ## Xml text to add 14 | [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'XmlEx')] 15 | [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'XmlElement')] 16 | [ValidateNotNullOrEmpty()] 17 | [System.String] $Text, 18 | 19 | ## Existing Xml element to add the text node to 20 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlElement')] 21 | [ValidateNotNull()] 22 | [System.Xml.XmlElement] $XmlElement, 23 | 24 | ## Returns the created XmlText object to the pipeline. By default, this cmdlet does not generate any output. 25 | [Parameter(ValueFromPipelineByPropertyName)] 26 | [System.Management.Automation.SwitchParameter] $PassThru 27 | ) 28 | begin { 29 | 30 | $callingFunction = (Get-PSCallStack)[2]; 31 | if ($callingFunction.FunctionName -eq 'New-XmlExDocument') { 32 | throw ($localized.XmlExInvalidCallWithinScopeError -f 'XmlText','XmlDocument','XmlElement'); 33 | } 34 | 35 | if ($PSCmdlet.ParameterSetName -eq 'XmlElement') { 36 | 37 | Write-Debug ("Inferring document from element '{0}'," -f $Name); 38 | $_xmlExCurrentDocument = $XmlElement.OwnerDocument; 39 | $_xmlExCurrentElement = $XmlElement; 40 | } 41 | 42 | if ($null -eq $_xmlExCurrentDocument) { 43 | throw ($localized.XmlExDocumentNotFoundError); 44 | } 45 | 46 | if ($null -eq $_xmlExCurrentElement) { 47 | throw ($localized.XmlExElementNotFoundError); 48 | } 49 | 50 | } #end begin 51 | process { 52 | 53 | $padding = ''; 54 | if ($_xmlExCurrentElementIndent) { 55 | $padding = ''.PadRight($_xmlExCurrentElementIndent +1); 56 | } 57 | $paddedMessage = '{0}{1}' -f $padding, ($localized.AddingTextNode -f $_xmlExCurrentElement.LocalName); 58 | Write-Verbose -Message $paddedMessage; 59 | 60 | $xmlTextNode = $_xmlExCurrentDocument.CreateTextNode($Text); 61 | [ref] $null = $_xmlExCurrentElement.AppendChild($xmlTextNode); 62 | 63 | if ($PassThru) { 64 | Write-Output -InputObject $xmlTextNode; 65 | } 66 | 67 | } #end process 68 | } #end function XmlText 69 | -------------------------------------------------------------------------------- /Src/Public/Format-XmlEx.ps1: -------------------------------------------------------------------------------- 1 | function Format-XmlEx { 2 | <# 3 | .SYNOPSIS 4 | Pretty prints a [System.Xml.XmlDocument] object 5 | .NOTES 6 | https://blogs.msdn.microsoft.com/powershell/2008/01/18/format-xml/ 7 | #> 8 | [CmdletBinding()] 9 | param ( 10 | ## Xml document to pretty print 11 | [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] 12 | [ValidateNotNull()] 13 | [System.Xml.XmlDocument] $XmlDocument, 14 | 15 | ## Xml indentation level 16 | [Parameter()] 17 | [System.Int32] $Indent = 2 18 | ) 19 | process { 20 | 21 | $stringReader = New-Object -TypeName 'System.IO.StringReader' -ArgumentList $XmlDocument.OuterXml; 22 | $xmlTextReader = New-Object -TypeName 'System.Xml.XmlTextReader' -ArgumentList $stringReader; 23 | 24 | $stringWriter = New-Object -TypeName 'System.IO.StringWriter'; 25 | $xmlTextWriter = New-Object -TypeName 'System.Xml.XmlTextWriter' -ArgumentList $stringWriter; 26 | $xmlTextWriter.Formatting = 'indented'; 27 | $xmlTextWriter.Indentation = $Indent; 28 | 29 | do { 30 | $xmlTextWriter.WriteNode($xmlTextReader, $false) 31 | } 32 | while ($xmlTextReader.Read()) 33 | 34 | $xmlTextReader.Close(); 35 | $stringReader.Close(); 36 | $xmlTextWriter.Flush(); 37 | $stringWriter.Flush(); 38 | 39 | Write-Output -InputObject $stringWriter.ToString(); 40 | 41 | } #end process 42 | } #end function Format-XmlEx 43 | -------------------------------------------------------------------------------- /Src/Public/New-XmlExDocument.ps1: -------------------------------------------------------------------------------- 1 | function New-XmlExDocument { 2 | <# 3 | .SYNOPSIS 4 | Creates a new XmlEx document. 5 | .DESCRIPTION 6 | The New-XmlExDocument cmdlet creates a new XmlEx document. 7 | #> 8 | [CmdletBinding()] 9 | [Alias('XmlDocument')] 10 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] 11 | [OutputType([System.Xml.XmlDocument])] 12 | param ( 13 | ## XmlEx document content 14 | [Parameter(ValueFromPipelineByPropertyName, Position = 0)] 15 | [ValidateNotNull()] 16 | [System.Management.Automation.ScriptBlock] $ScriptBlock 17 | ) 18 | process { 19 | 20 | Write-Verbose -Message ($localized.CreatingDocument); 21 | $_xmlExCurrentDocument = New-Object -TypeName 'System.Xml.XmlDocument'; 22 | 23 | $currentWhatIfPreference = $WhatIfPreference; 24 | $WhatIfPreference = $false; 25 | Set-Variable -Name _xmlExCurrentElementIndent -Value 0 -Scope Script; 26 | 27 | ## Set the document namespaces 28 | Set-Variable -Name _xmlExDocumentNamespaces -Value @{ } -Scope Script -Confirm:$false -Force; 29 | Set-Variable -Name _xmlExCurrentNamespace -Value $null -Scope Script; 30 | 31 | ## Set the current element to the root 32 | Set-Variable -Name _xmlExCurrentElement -Value $_xmlExCurrentDocument -Scope Script; 33 | $WhatIfPreference = $currentWhatIfPreference; 34 | 35 | if ($PSBoundParameters.ContainsKey('ScriptBlock')) { 36 | [ref] $null = & $ScriptBlock; 37 | } 38 | 39 | ## We can't add attributes until we have a root element. 40 | foreach ($namespace in $_xmlExDocumentNamespaces.Keys) { 41 | 42 | if ($null -eq $_xmlExCurrentDocument.DocumentElement) { 43 | throw ($localized.XmlExNamespaceMissingXmlElementError); 44 | } 45 | else { 46 | 47 | $xmlNamespace = $_xmlExDocumentNamespaces[$namespace]; 48 | Write-Verbose -Message ($localized.AddingDocumentNamespace -f $xmlNamespace.DisplayName); 49 | [ref] $null = $_xmlExCurrentDocument.DocumentElement.SetAttribute( 50 | $namespace, $xmlNamespace.Uri); 51 | } 52 | } #end foreach namespace 53 | 54 | Write-Verbose -Message ($localized.FinalizingDocument); 55 | Write-Output -InputObject $_xmlExCurrentDocument; 56 | 57 | } #end process 58 | } #end functon XmlDocument 59 | -------------------------------------------------------------------------------- /Src/Public/Set-XmlExConfigKeyValue.ps1: -------------------------------------------------------------------------------- 1 | function Set-XmlExConfigKeyValue { 2 | <# 3 | .SYNOPSIS 4 | Ensures an Xml document contains a Xml element/attribute. 5 | #> 6 | [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Path')] 7 | param ( 8 | # Specifies a path to one or more locations. Wildcards are permitted. 9 | [Parameter(Mandatory, Position = 0, ParameterSetName = 'Path', ValueFromPipeline, ValueFromPipelineByPropertyName)] 10 | [ValidateNotNullOrEmpty()] 11 | [SupportsWildcards()] 12 | [System.String[]] $Path, 13 | 14 | # Specifies a path to one or more locations. Unlike the Path parameter, the value of the LiteralPath parameter is 15 | # used exactly as it is typed. No characters are interpreted as wildcards. If the path includes escape characters, 16 | # enclose it in single quotation marks. Single quotation marks tell Windows PowerShell not to interpret any 17 | # characters as escape sequences. 18 | [Parameter(Mandatory, Position = 0, ParameterSetName = 'LiteralPath', ValueFromPipelineByPropertyName)] 19 | [Alias('PSPath')] 20 | [ValidateNotNullOrEmpty()] 21 | [System.String[]] $LiteralPath, 22 | 23 | ## Specifies the XPath location of the parent Xml element within the document to update. 24 | [Parameter(Mandatory, ValueFromPipelineByPropertyName)] 25 | [System.String] $XPath, 26 | 27 | ## Specifies the name of the Xml element or Xml attribute to update. 28 | [Parameter(Mandatory, ValueFromPipelineByPropertyName)] 29 | [System.String] $Name, 30 | 31 | ## Specifies the value of the Xml element or Xml attribute to update. 32 | [Parameter(ValueFromPipelineByPropertyName)] 33 | [System.String] $Value, 34 | 35 | ## Specifies the target is an attribute. Defaults to an element. 36 | [Parameter(ValueFromPipelineByPropertyName)] 37 | [System.Management.Automation.SwitchParameter] $IsAttribute, 38 | 39 | ## Specifies the target Xml document file should be created if it does not exist. 40 | [Parameter(ValueFromPipelineByPropertyName)] 41 | [System.Management.Automation.SwitchParameter] $Force 42 | ) 43 | begin { 44 | 45 | [ref] $null = $PSBoundParameters.Remove('Path'); 46 | [ref] $null = $PSBoundParameters.Remove('LiteralPath'); 47 | $paths = @(); 48 | 49 | } 50 | process { 51 | 52 | if ($PSCmdlet.ParameterSetName -eq 'Path') { 53 | 54 | foreach ($filePath in $Path) { 55 | 56 | if (-not $Force) { 57 | 58 | if (-not (Test-Path -Path $filePath)) { 59 | 60 | $errorMessage = $localized.CannotFindPathError -f $filePath; 61 | $ex = New-Object System.Management.Automation.ItemNotFoundException $errorMessage; 62 | $category = [System.Management.Automation.ErrorCategory]::ObjectNotFound; 63 | $errorRecord = New-Object System.Management.Automation.ErrorRecord $ex, 'PathNotFound', $category, $filePath; 64 | $PSCmdlet.WriteError($errorRecord); 65 | continue; 66 | } 67 | 68 | # Resolve any wildcards that might be in the path 69 | $provider = $null; 70 | $paths += $psCmdlet.SessionState.Path.GetResolvedProviderPathFromPSPath($filePath, [ref] $provider); 71 | 72 | } 73 | else { 74 | 75 | $paths += $PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($filePath); 76 | 77 | } 78 | 79 | } #end foreach path 80 | } 81 | else { 82 | 83 | foreach ($filePath in $LiteralPath) { 84 | 85 | if (-not $Force) { 86 | 87 | if (-not (Test-Path -LiteralPath $filePath)) { 88 | 89 | $errorMessage = $localized.CannotFindPathError -f $filePath; 90 | $ex = New-Object System.Management.Automation.ItemNotFoundException $errorMessage; 91 | $category = [System.Management.Automation.ErrorCategory]::ObjectNotFound; 92 | $errorRecord = New-Object System.Management.Automation.ErrorRecord $ex, 'PathNotFound', $category, $filePath; 93 | $PSCmdlet.WriteError($errorRecord); 94 | continue; 95 | } 96 | 97 | } 98 | 99 | # Resolve any relative paths 100 | $paths += $PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($filePath); 101 | 102 | } #end foreach literal path 103 | } 104 | 105 | } #end process 106 | end { 107 | 108 | foreach ($filePath in $paths) { 109 | 110 | Write-Verbose -Message ($localized.ProcessingDocument -f $filePath); 111 | $xmlDocument = Assert-XmlExFilePath -Path $filePath -Ensure 'Present';; 112 | Assert-XmlExXPath -XmlDocument $xmlDocument @PSBoundParameters; 113 | 114 | $verboseMessage = $localized.SavingDocument -f $filePath; 115 | $warningConfirmationMessage = $localized.ShouldProcessWarning; 116 | $warningDescriptionMessage = $localized.ShouldProcessOperationWarning -f 'Save', $filePath; 117 | 118 | if ($Force -or ($PSCmdlet.ShouldProcess($verboseMessage, $warningConfirmationMessage, $warningDescriptionMessage))) { 119 | 120 | $xmlDocument.Save($filePath); 121 | } 122 | } 123 | 124 | } #end 125 | } #end function 126 | -------------------------------------------------------------------------------- /Src/Public/Set-XmlExDeclaration.ps1: -------------------------------------------------------------------------------- 1 | function Set-XmlExDeclaration { 2 | <# 3 | .SYNOPSIS 4 | Sets the Xml declaration. 5 | .DESCRIPTION 6 | The Set-XmlExDeclaration cmdlet set the Xml declaration on a XmlEx document. 7 | #> 8 | [CmdletBinding(DefaultParameterSetName = 'XmlEx')] 9 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] 10 | [Alias('XmlDeclaration')] 11 | [OutputType([System.Xml.XmlDeclaration])] 12 | param ( 13 | ## Xml document 'version' declaration 14 | [Parameter(ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlEx')] 15 | [Parameter(ValueFromPipelineByPropertyName, Position = 0, ParameterSetName = 'XmlDocument')] 16 | [ValidateSet('1.0')] 17 | [System.String] $Version, 18 | 19 | ## Xml document 'encoding' declaration 20 | [Parameter(ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlEx')] 21 | [Parameter(ValueFromPipelineByPropertyName, Position = 1, ParameterSetName = 'XmlDocument')] 22 | [ValidateNotNullOrEmpty()] 23 | [System.String] $Encoding, 24 | 25 | ## Xml document 'standalone' declaration 26 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlEx')] 27 | [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocument')] 28 | [ValidateSet('Yes','No')] 29 | [System.String] $Standalone, 30 | 31 | ## Xml document to add the declaration to 32 | [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'XmlDocument')] 33 | [ValidateNotNull()] 34 | [System.Xml.XmlDocument] $XmlDocument, 35 | 36 | ## Returns the created XmlDecalration object to the pipeline. By default, this cmdlet does not generate any output. 37 | [Parameter(ValueFromPipelineByPropertyName)] 38 | [System.Management.Automation.SwitchParameter] $PassThru 39 | ) 40 | begin { 41 | 42 | if ($PSCmdlet.ParameterSetName -eq 'XmlDocument') { 43 | $_xmlExCurrentDocument = $XmlDocument; 44 | } 45 | 46 | if ($null -eq $_xmlExCurrentDocument) { 47 | throw ($localized.XmlExDocumentNotFoundError); 48 | } 49 | 50 | } 51 | process { 52 | 53 | if ($PSCmdlet.ParameterSetName -eq 'XmlEx') { 54 | $callingFunction = (Get-PSCallStack)[2]; 55 | if ($callingFunction.FunctionName -ne 'New-XmlExDocument') { 56 | throw ($localized.XmlExInvalidCallOutsideScopeError -f 'XmlDecalration','XmlDocument'); 57 | } 58 | } 59 | 60 | if (-not $PSBoundParameters.ContainsKey('Version')) { 61 | $Version = '1.0'; 62 | } 63 | 64 | $xmlDeclaration = $_xmlExCurrentDocument.CreateXmlDeclaration($Version, $Encoding, $Standalone); 65 | [ref] $null = $_xmlExCurrentDocument.AppendChild($xmlDeclaration); 66 | 67 | if ($PassThru) { 68 | Write-Output -InputObject $xmlDeclaration; 69 | } 70 | 71 | } 72 | } #end function Set-XmlExDeclaration 73 | -------------------------------------------------------------------------------- /Tests/Linting/FileEncoding.Tests.ps1: -------------------------------------------------------------------------------- 1 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..").Path; 2 | Describe 'Linting\FileEncoding' { 3 | 4 | $excludedPaths = @( 5 | '.git*', 6 | '.vscode', 7 | 'Docs', 8 | 'DSCResources', # We'll take the public DSC resources as-is 9 | 'Release', 10 | '*.png', 11 | '*.enc', 12 | '*.exe', 13 | '*.dll', 14 | 'appveyor-tools', 15 | 'TestResults.xml' 16 | ); 17 | 18 | function TestEncodingPath { 19 | [CmdletBinding()] 20 | param ( 21 | [Parameter(Mandatory, ValueFromPipeline)] 22 | [System.String] $Path, 23 | 24 | [System.String[]] $Exclude 25 | ) 26 | process 27 | { 28 | $WarningPreference = 'SilentlyContinue' 29 | Get-ChildItem -Path $Path -Exclude $Exclude | 30 | ForEach-Object { 31 | if ($_ -is [System.IO.FileInfo]) 32 | { 33 | if ($_.Name -ne 'Resolve-ProgramFilesFolder.ps1') 34 | { 35 | It "File '$($_.FullName.Replace($repoRoot,''))' uses UTF-8 (no BOM) encoding" { 36 | $encoding = (Get-FileEncoding -Path $_.FullName -WarningAction SilentlyContinue).HeaderName 37 | $encoding | Should Be 'us-ascii' 38 | } 39 | } 40 | } 41 | elseif ($_ -is [System.IO.DirectoryInfo]) 42 | { 43 | TestEncodingPath -Path $_.FullName -Exclude $Exclude 44 | } 45 | } 46 | } #end process 47 | } #end function 48 | 49 | Get-ChildItem -Path $repoRoot -Exclude $excludedPaths | 50 | ForEach-Object { 51 | TestEncodingPath -Path $_.FullName -Exclude $excludedPaths 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Tests/Linting/PSScriptAnalyzer.Tests.ps1: -------------------------------------------------------------------------------- 1 | #requires -Version 4 2 | #requires -Modules PSScriptAnalyzer 3 | 4 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..").Path; 5 | Describe 'Linting\PSScriptAnalyzer' { 6 | 7 | Get-ChildItem -Path "$repoRoot\Src" -Recurse -File | ForEach-Object { 8 | It "File '$($_.Name)' passes PSScriptAnalyzer rules" { 9 | $result = Invoke-ScriptAnalyzer -Path $_.FullName -Severity Warning | Select-Object -ExpandProperty Message 10 | $result | Should BeNullOrEmpty 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Linting/Style.Tests.ps1: -------------------------------------------------------------------------------- 1 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..").Path; 2 | 3 | Describe 'Linting\Style' -Tags "Style" { 4 | 5 | $excludedPaths = @( 6 | '.git*', 7 | '.vscode', 8 | 'DSCResources', # We'll take the public DSC resources as-is 9 | 'Release', 10 | '*.png', 11 | '*.enc', 12 | '*.dll', 13 | 'appveyor-tools', 14 | 'TestResults.xml', 15 | 'Tests', 16 | 'Docs' 17 | ); 18 | 19 | function TestStylePath { 20 | [CmdletBinding()] 21 | param ( 22 | [Parameter(Mandatory, ValueFromPipeline)] 23 | [System.String] $Path, 24 | 25 | [System.String[]] $Exclude 26 | ) 27 | process 28 | { 29 | Get-ChildItem -Path $Path -Exclude $Exclude | 30 | ForEach-Object { 31 | if ($_ -is [System.IO.FileInfo]) 32 | { 33 | It "File '$($_.FullName.Replace($repoRoot,''))' contains no trailing whitespace" { 34 | $badLines = @( 35 | $lines = [System.IO.File]::ReadAllLines($_.FullName) 36 | $lineCount = $lines.Count 37 | 38 | for ($i = 0; $i -lt $lineCount; $i++) { 39 | if ($lines[$i] -match '\s+$') { 40 | 'File: {0}, Line: {1}' -f $_.FullName, ($i + 1) 41 | } 42 | } 43 | ) 44 | 45 | @($badLines).Count | Should Be 0 46 | } 47 | 48 | It "File '$($_.FullName.Replace($repoRoot,''))' ends with a newline" { 49 | 50 | $string = [System.IO.File]::ReadAllText($_.FullName) 51 | ($string.Length -gt 0 -and $string[-1] -ne "`n") | Should Be $false 52 | } 53 | } 54 | elseif ($_ -is [System.IO.DirectoryInfo]) 55 | { 56 | TestStylePath -Path $_.FullName -Exclude $Exclude 57 | } 58 | } 59 | } #end process 60 | } #end function 61 | 62 | Get-ChildItem -Path $repoRoot -Exclude $excludedPaths | 63 | ForEach-Object { 64 | TestStylePath -Path $_.FullName -Exclude $excludedPaths 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /Tests/Unit/Src/Public/Add-XmlExAttribute.Tests.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | #requires -Version 3 5 | 6 | $moduleName = 'XmlEx'; 7 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..\..\..").Path; 8 | Import-Module (Join-Path -Path $repoRoot -ChildPath "$moduleName.psm1") -Force; 9 | 10 | Describe 'Src\Add-XmlExAttribute' { 11 | 12 | It 'returns [System.Xml.XmlAttribute] object type' { 13 | 14 | $testAttributeName = 'TestAttribute'; 15 | $testAttributeValue = 'TestAttributeValue'; 16 | $testComment = 'RequiredToCoerceElementAsXmlElementOtherwiseReturnedAsString'; 17 | $testElement = 'TestElement'; 18 | $xmlDocument = XmlDocument { 19 | XmlElement -Name $testElement { 20 | XmlComment -Comment $testComment 21 | } 22 | }; 23 | 24 | $result = XmlAttribute -Name $testAttributeName -Value $testAttributeValue -XmlElement $xmlDocument.$testElement -PassThru; 25 | 26 | $result -is [System.Xml.XmlAttribute] | Should Be $true; 27 | } 28 | 29 | It 'adds attribute to existing element' { 30 | 31 | $testAttributeName = 'TestAttribute'; 32 | $testAttributeValue = 'TestAttributeValue'; 33 | $testComment = 'RequiredToCoerceElementAsXmlElementOtherwiseReturnedAsString'; 34 | $testElement = 'TestElement'; 35 | $expected = '<{0} {1}="{2}">' -f $testElement, $testAttributeName, $testAttributeValue, $testComment; 36 | 37 | $xmlDocument = XmlDocument { 38 | XmlElement -Name $testElement { 39 | XmlComment -Comment $testComment 40 | } 41 | }; 42 | XmlAttribute -Name $testAttributeName -Value $testAttributeValue -XmlElement $xmlDocument.$testElement; 43 | 44 | $xmlDocument.OuterXml | Should Match $expected; 45 | } 46 | 47 | It 'adds attribute in a new document' { 48 | 49 | $testAttributeName = 'TestAttribute'; 50 | $testAttributeValue = 'TestAttributeValue'; 51 | $testElement = 'TestElement'; 52 | $expected = '<{0} {1}="{2}" />' -f $testElement, $testAttributeName, $testAttributeValue; 53 | 54 | $xmlDocument = XmlDocument { 55 | XmlElement -Name $testElement { 56 | XmlAttribute -Name $testAttributeName -Value $testAttributeValue 57 | } 58 | }; 59 | 60 | $xmlDocument.OuterXml | Should Match $expected; 61 | } 62 | 63 | It 'adds attribute with a namespace' { 64 | 65 | $testAttributeName = 'TestAttribute'; 66 | $testAttributeValue = 'TestAttributeValue'; 67 | $testElement = 'TestElement'; 68 | $testNamespaceUri = 'http://virtualengine.co.uk/namespace' 69 | 70 | $expectedAttribute = 'd1p1:{0}="{1}"' -f $testAttributeName, $testAttributeValue; 71 | $expectedNamespace = 'xmlns:d1p1="{0}"' -f $testNamespaceUri; 72 | 73 | $xmlDocument = XmlDocument { 74 | XmlElement -Name $testElement { 75 | XmlAttribute -Name $testAttributeName -Value $testAttributeValue -Namespace $testNamespaceUri; 76 | } 77 | }; 78 | 79 | $xmlDocument.OuterXml | Should Match $expectedAttribute; 80 | $xmlDocument.OuterXml | Should Match $expectedNamespace; 81 | } 82 | 83 | It 'adds attribute with a prefixed namespace' { 84 | 85 | $testAttributeName = 'TestAttribute'; 86 | $testAttributeValue = 'TestAttributeValue'; 87 | $testElement = 'TestElement'; 88 | $testNamespaceUri = 'http://virtualengine.co.uk/namespace' 89 | $testNamespacePrefix = 'v' 90 | 91 | $expectedAttribute = '{0}:{1}="{2}"' -f $testNamespacePrefix, $testAttributeName, $testAttributeValue; 92 | $expectedNamespace = 'xmlns:{0}="{1}"' -f $testNamespacePrefix, $testNamespaceUri; 93 | 94 | $xmlDocument = XmlDocument { 95 | XmlElement -Name $testElement { 96 | XmlAttribute -Name $testAttributeName -Value $testAttributeValue -Prefix $testNamespacePrefix -Namespace $testNamespaceUri; 97 | } 98 | }; 99 | 100 | $xmlDocument.OuterXml | Should Match $expectedAttribute; 101 | $xmlDocument.OuterXml | Should Match $expectedNamespace; 102 | } 103 | 104 | It 'does not add attribute prefix when specified' { 105 | $testAttributeName = 'TestAttribute'; 106 | $testAttributeValue = 'TestAttributeValue'; 107 | $testElement = 'TestElement'; 108 | $testPrefix = 've'; 109 | $testNamespaceUri = 'http://virtualengine.co.uk/namespace' 110 | 111 | $xmlDocument = XmlDocument { 112 | XmlNamespace -Prefix $testPrefix -Uri $testNamespaceUri -IsDefault 113 | XmlElement -Name $testElement -Namespace $testNamespaceUri { 114 | XmlAttribute -Name $testAttributeName -Value $testAttributeValue -NoPrefix 115 | } 116 | }; 117 | $xmlDocument.OuterXml | Should Not Match "$($testprefix):$($testAttributeName)" 118 | } 119 | 120 | It 'throws when adding attribute when document contains no root element' { 121 | 122 | $testAttributeName = 'TestAttribute'; 123 | $testAttributeValue = 'TestAttributeValue'; 124 | { 125 | XmlDocument { 126 | XmlAttribute -Name $testAttributeName -Value $testAttributeValue 127 | } 128 | } | Should Throw "Cannot add a 'XmlAttribute' to a document without a root element"; 129 | } 130 | 131 | } #end describe Src\Add-XmlExAttribute 132 | -------------------------------------------------------------------------------- /Tests/Unit/Src/Public/Add-XmlExComment.Tests.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | #requires -Version 3 5 | 6 | $moduleName = 'XmlEx'; 7 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..\..\..").Path; 8 | Import-Module (Join-Path -Path $repoRoot -ChildPath "$moduleName.psm1") -Force; 9 | 10 | Describe 'Src\Add-XmlExComment' { 11 | 12 | It 'returns [System.Xml.XmlComment] object type' { 13 | 14 | $testComment = 'Test Comment'; 15 | $xmlDocument = XmlDocument { 16 | XmlElement -Name 'TestElement' { 17 | XmlAttribute -Name 'RequiredToCoerceElementAsXmlElement' -Value 'OtherwiseReturnedAsString' 18 | } 19 | }; 20 | 21 | $result = XmlComment -Comment $testComment -XmlElement $xmlDocument.TestElement -PassThru; 22 | 23 | $result -is [System.Xml.XmlComment] | Should Be $true; 24 | } 25 | 26 | It 'creates "" comment' { 27 | 28 | $testComment = 'Test Comment'; 29 | $expected = '' -f $testComment; 30 | 31 | $result = XmlDocument { 32 | XmlComment $testComment 33 | }; 34 | 35 | $result.OuterXml | Should Match $expected; 36 | 37 | } 38 | 39 | } #end describe Src\Add-XmlExComment 40 | -------------------------------------------------------------------------------- /Tests/Unit/Src/Public/Add-XmlExElement.Tests.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | #requires -Version 3 5 | 6 | $moduleName = 'XmlEx'; 7 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..\..\..").Path; 8 | Import-Module (Join-Path -Path $repoRoot -ChildPath "$moduleName.psm1") -Force; 9 | 10 | Describe 'Src\Add-XmlExElement' { 11 | 12 | It 'returns [System.Xml.XmlElement] object type' { 13 | 14 | $testElement = 'TestElement'; 15 | $xmlDocument = XmlDocument { }; 16 | 17 | $result = XmlElement $testElement -XmlDocument $xmlDocument -PassThru; 18 | 19 | $result -is [System.Xml.XmlElement] | Should Be $true; 20 | } 21 | 22 | It 'creates an element' { 23 | 24 | $testElement = 'TestElement'; 25 | $testComment = 'RequiredToCoerceAcceleratorToXmlElement'; 26 | $expected = '<{0}><{1}>' -f $testElement, $testNamespaceUri; 59 | $result = XmlDocument { 60 | XmlElement $testElement -Namespace $testNamespaceUri 61 | } 62 | 63 | $result.OuterXml | Should Match $expected; 64 | } 65 | 66 | It 'creates an element with a prefixed namespace' { 67 | 68 | $testElement = 'TestElement'; 69 | $testNamespaceUri = 'http://virtualengine.co.uk/namespace'; 70 | $testNamespacePrefix = 'v'; 71 | $expected = '<{0}:{1} xmlns:{0}="{2}" />' -f $testNamespacePrefix, $testElement, $testNamespaceUri; 72 | $result = XmlDocument { 73 | XmlElement $testElement -Prefix $testNamespacePrefix -Namespace $testNamespaceUri 74 | } 75 | 76 | $result.OuterXml | Should Match $expected; 77 | } 78 | 79 | It 'adds an element to an existing [XmlElement]' { 80 | $testRootElement = 'TestRootElement'; 81 | $testNestedElement = 'TestNestedElement'; 82 | $testComment = 'RequiredToCoerceAcceleratorToXmlElement'; 83 | $expected = '<{0}><{2} />' -f $testRootElement, $testComment, $testNestedElement; 84 | $xmlDocument = XmlDocument { 85 | XmlElement $testRootElement { 86 | XmlComment $testComment 87 | } 88 | } 89 | 90 | $null = XmlElement -Name $testNestedElement -XmlElement $xmlDocument.$testRootElement 91 | $xmlDocument.OuterXml | Should Match $expected; 92 | } 93 | 94 | It 'does not add element prefix when specified' { 95 | $testElement = 'TestElement'; 96 | $nestedTestElement = 'NestedTestElement'; 97 | $testNamespaceUri = 'http://virtualengine.co.uk/namespace'; 98 | $testNamespacePrefix = 'v'; 99 | $expected = '<{0} />' -f $nestedTestElement; 100 | 101 | $xmlDocument = XmlDocument { 102 | XmlElement $testElement -Prefix $testNamespacePrefix -Namespace $testNamespaceUri { 103 | XmlElement -Name $nestedTestElement -NoPrefix 104 | } 105 | } 106 | 107 | $xmlDocument.OuterXml | Should Match $expected 108 | } 109 | 110 | } #end describe Src\Add-XmlExElement 111 | -------------------------------------------------------------------------------- /Tests/Unit/Src/Public/Add-XmlExNamespace.Tests.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | #requires -Version 3 5 | 6 | $moduleName = 'XmlEx'; 7 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..\..\..").Path; 8 | Import-Module (Join-Path -Path $repoRoot -ChildPath "$moduleName.psm1") -Force; 9 | 10 | Describe 'Src\Add-XmlExNamespace' { 11 | 12 | It 'Creates [System.Xml.XmlDocument] with a namespace' { 13 | $testNamespaceUri = 'http://virtualengine.co.uk/namespace'; 14 | $expected = 'xmlns="{0}"' -f $testNamespaceUri; 15 | 16 | $result = XmlDocument { 17 | XmlNamespace -Uri $testNamespaceUri; 18 | XmlElement 'RequiredToAddNamespace'; 19 | }; 20 | 21 | $result.OuterXml | Should Match $expected; 22 | } 23 | 24 | It 'Creates [System.Xml.XmlDocument] with a prefixed namespace' { 25 | $testNamespaceUri = 'http://virtualengine.co.uk/namespace'; 26 | $testNamespacePrefix = 've'; 27 | $expected = 'xmlns:{0}="{1}"' -f $testNamespacePrefix, $testNamespaceUri; 28 | 29 | $result = XmlDocument { 30 | XmlNamespace -Prefix $testNamespacePrefix -Uri $testNamespaceUri; 31 | XmlElement 'RequiredToAddNamespace'; 32 | }; 33 | 34 | $result.OuterXml | Should Match $expected; 35 | } 36 | 37 | It 'throws when calling "XmlNamespace" outside of "XmlDocument" script block' { 38 | $testNamespaceUri = 'http://virtualengine.co.uk/namespace'; 39 | $xmlDocument = XmlDocument { }; 40 | 41 | { XmlNamespace -Uri 'http://virtualengine.co.uk/namespace' -XmlDocument $xmlDocument } | 42 | Should Throw "You cannot call 'XmlNamespace' outside the 'XmlDocument' scope."; 43 | } 44 | 45 | } #end describe Src\Add-XmlExNamespace 46 | -------------------------------------------------------------------------------- /Tests/Unit/Src/Public/Add-XmlExText.Tests.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | #requires -Version 3 5 | 6 | $moduleName = 'XmlEx'; 7 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..\..\..").Path; 8 | Import-Module (Join-Path -Path $repoRoot -ChildPath "$moduleName.psm1") -Force; 9 | 10 | Describe 'Src\Add-XmlExText' { 11 | 12 | It 'returns [System.Xml.XmlText] object type' { 13 | 14 | $testText = 'Test text'; 15 | $testElement = 'TestElement'; 16 | $xmlDocument = XmlDocument { 17 | XmlElement -Name testElement { 18 | XmlAttribute -Name 'RequiredToCoerceElementAsXmlElement' -Value 'OtherwiseReturnedAsString' 19 | } 20 | }; 21 | 22 | $result = XmlText -Text $testText -XmlElement $xmlDocument.$testElement -PassThru; 23 | 24 | $result -is [System.Xml.XmlText] | Should Be $true; 25 | } 26 | 27 | It 'creates element text node' { 28 | 29 | $testText = 'Test text'; 30 | $testElement = 'TestElement'; 31 | $expected = '<{0}>{1}' -f $testElement, $testText; 32 | 33 | $result = XmlDocument { 34 | XmlElement $testElement { 35 | XmlText $testText 36 | } 37 | }; 38 | 39 | $result.OuterXml | Should Match $expected; 40 | 41 | } 42 | 43 | It 'throws when adding text to the document root' { 44 | 45 | $testText = 'Test text'; 46 | 47 | { 48 | XmlDocument { 49 | XmlText $testText 50 | } 51 | } | Should Throw "You cannot call 'XmlText' from within the 'XmlDocument' scope" 52 | } 53 | 54 | } #end describe Src\Add-XmlText 55 | -------------------------------------------------------------------------------- /Tests/Unit/Src/Public/New-XmlExDocument.Tests.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | #requires -Version 3 5 | 6 | $moduleName = 'XmlEx'; 7 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..\..\..").Path; 8 | Import-Module (Join-Path -Path $repoRoot -ChildPath "$moduleName.psm1") -Force; 9 | 10 | Describe 'Src\New-XmlExDocument' { 11 | 12 | It 'creates a [System.Xml.XmlDocument] object type' { 13 | 14 | $result = XmlDocument; 15 | 16 | $result -is [System.Xml.XmlDocument] | Should Be $true; 17 | } 18 | 19 | It 'calls nested "ScriptBlock"' { 20 | 21 | $testComment = 'Test Comment' 22 | 23 | $result = XmlDocument { XmlComment $testComment }; 24 | 25 | $result.OuterXml | Should Match $testComment; 26 | } 27 | 28 | It 'throws adding "XmlNamespace" to an empty "XmlDocument"' { 29 | 30 | { XmlDocument { 31 | XmlNamespace -Uri 'http://virtualengine.co.uk/namespace' 32 | } 33 | } | Should Throw "Cannot add a 'XmlNamespace' to a document without a root element."; 34 | 35 | } 36 | 37 | } #end describe Src\New-XmlExDocument 38 | -------------------------------------------------------------------------------- /Tests/Unit/Src/Public/Set-XmlExDeclaration.Tests.ps1: -------------------------------------------------------------------------------- 1 | [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] 2 | param() 3 | 4 | #requires -Version 3 5 | 6 | $moduleName = 'XmlEx'; 7 | $repoRoot = (Resolve-Path "$PSScriptRoot\..\..\..\..").Path; 8 | Import-Module (Join-Path -Path $repoRoot -ChildPath "$moduleName.psm1") -Force; 9 | 10 | Describe 'Src\Set-XmlExDeclaration' { 11 | 12 | It 'returns [System.Xml.XmlDeclaration] object type' { 13 | 14 | $xmlDocument = XmlDocument { } 15 | 16 | $result = XmlDeclaration -XmlDocument $xmlDocument -PassThru; 17 | 18 | $result -is [System.Xml.XmlDeclaration] | Should Be $true; 19 | } 20 | 21 | It 'adds version number by default' { 22 | 23 | $expected = 'version="1.0"'; 24 | 25 | $result = XmlDocument { 26 | XmlDeclaration 27 | } 28 | 29 | $result.OuterXml | Should Match $expected; 30 | } 31 | 32 | It 'adds encoding declaration when specified' { 33 | 34 | $testEncoding = 'utf-8'; 35 | $expected = 'encoding="{0}"' -f $testEncoding; 36 | 37 | $result = XmlDocument { 38 | XmlDeclaration -Encoding $testEncoding 39 | } 40 | 41 | $result.OuterXml | Should Match $expected; 42 | } 43 | 44 | It 'adds standalone declaration when specified' { 45 | 46 | $testStandalone = 'yes'; 47 | $expected = 'standalone="{0}"' -f $testStandalone; 48 | 49 | $result = XmlDocument { 50 | XmlDeclaration -Standalone $testStandalone 51 | } 52 | 53 | $result.OuterXml | Should Match $expected; 54 | } 55 | 56 | It 'throws when called outside the XmlDocument scope' { 57 | 58 | { 59 | XmlDocument { 60 | XmlElement 'notallowed' { 61 | XmlDeclaration 62 | } 63 | } 64 | } | Should Throw "You cannot call 'XmlDecalration' outside the 'XmlDocument' scope"; 65 | } 66 | 67 | } #end describe Src\Set-XmlExDeclaration 68 | -------------------------------------------------------------------------------- /VE_Certificate_2019.pfx.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iainbrighton/XmlEx/4a686180edcef207ef571cb7dbc57f6d8f12bd49/VE_Certificate_2019.pfx.enc -------------------------------------------------------------------------------- /XmlEx.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | xmlex 5 | XmlEx 6 | 0.0.0 7 | Iain Brighton 8 | Virtual Engine 9 | The XmlEx module implements a simple PowerShell DSL for XML documents. 10 | The XmlEx module implements a simple PowerShell DSL for the creation and manipulation of XML documents. 11 | http://github.com/iainbrighton/XmlEx 12 | (c) 2018 Virtual Engine Limited. All rights reserved. 13 | MIT 14 | false 15 | XML Powerhell DSL Extension Framework 16 | 17 | 18 | -------------------------------------------------------------------------------- /XmlEx.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | RootModule = 'XmlEx.psm1'; 3 | ModuleVersion = '0.9.5'; 4 | GUID = '2a98010d-0e5f-4779-b3b5-5f0b66fea533'; 5 | Author = 'Iain Brighton'; 6 | CompanyName = 'Virtual Engine'; 7 | Copyright = '(c) 2018 Iain Brighton. All rights reserved.'; 8 | Description = 'The XmlEx module implements a simple PowerShell DSL for the creation and manipulation of XML documents.'; 9 | PowerShellVersion = '3.0'; 10 | AliasesToExport = @( 11 | 'XmlAttribute', 12 | 'XmlComment', 13 | 'XmlDeclaration', 14 | 'XmlDocument', 15 | 'XmlElement', 16 | 'XmlNamespace', 17 | 'XmlText' 18 | ); 19 | FunctionsToExport = @( 20 | 'Add-XmlExAttribute', 21 | 'Add-XmlExComment', 22 | 'Add-XmlExElement', 23 | 'Add-XmlExNamespace', 24 | 'Add-XmlExText', 25 | 'Format-XmlEx', 26 | 'New-XmlExDocument', 27 | 'Set-XmlExDeclaration', 28 | 'Set-XmlExConfigKeyValue' 29 | ); 30 | PrivateData = @{ 31 | PSData = @{ # Private data to pass to the module specified in RootModule/ModuleToProcess 32 | Tags = @('XML','Powershell','Extension','DSL','Framework'); 33 | LicenseUri = 'https://github.com/IainBrighton/XmlEx/blob/master/LICENSE'; 34 | ProjectUri = 'https://github.com/IainBrighton/XmlEx'; 35 | IconUri = 'https://raw.githubusercontent.com/IainBrighton/XmlEx/master/xml-tool-icon-53260.png'; 36 | } # End of PSData hashtable 37 | } # End of PrivateData hashtable 38 | } 39 | -------------------------------------------------------------------------------- /XmlEx.psm1: -------------------------------------------------------------------------------- 1 | ## Import localisation strings 2 | if (Test-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath $PSUICulture)) 3 | { 4 | $importLocalizedDataParams = @{ 5 | FileName = 'XmlEx.Resources.psd1'; 6 | BaseDirectory = Join-Path -Path $PSScriptRoot -ChildPath $PSUICulture; 7 | } 8 | } 9 | else 10 | { 11 | # fallback to en-US 12 | $importLocalizedDataParams = @{ 13 | FileName = 'XmlEx.Resources.psd1'; 14 | UICulture = 'en-US'; 15 | BaseDirectory = Join-Path -Path $PSScriptRoot -ChildPath 'en-US'; 16 | } 17 | } 18 | Import-LocalizedData -BindingVariable 'localized' @importLocalizedDataParams; 19 | 20 | ## Import the \Lib files. This permits loading of the module's functions for unit testing, without having to unload/load the module. 21 | $moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path -Parent; 22 | $moduleSrcPath = Join-Path -Path $moduleRoot -ChildPath 'Src'; 23 | Get-ChildItem -Path $moduleSrcPath -Include '*.ps1' -Recurse | 24 | ForEach-Object { 25 | Write-Verbose -Message ('Importing library\source file ''{0}''.' -f $_.FullName); 26 | . $_.FullName; 27 | } 28 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | #---------------------------------# 2 | # environment configuration # 3 | #---------------------------------# 4 | 5 | version: 0.9.{build} 6 | environment: 7 | gallery_api_key: 8 | secure: WeDp1yZJECZBjjW+22A8lA8+gmz+wiYostPKtU4pdLXORfK//eJCdR7f0k3oJ+2r 9 | certificate_secret: 10 | secure: 2NeBUwfDSJomxCyxUlwnqw== 11 | 12 | install: 13 | - ps: Write-Verbose -Message "PowerShell version $($PSVersionTable.PSVersion)" -Verbose 14 | - ps: Install-Module -Name Pester, PSSCriptAnalyzer, PSake, VirtualEngine.Build -Scope CurrentUser -Force -AllowClobber -Verbose 15 | - ps: $null = Invoke-Expression ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) 16 | 17 | build: false 18 | 19 | on_finish: 20 | - ps: | 21 | Invoke-PSake -BuildFile .\Build.PSake.ps1 -TaskList Appveyor 22 | 23 | for: 24 | 25 | - 26 | branches: 27 | only: 28 | - dev 29 | 30 | test_script: 31 | - ps: | 32 | Invoke-PSake -BuildFile .\Build.PSake.ps1 -TaskList Test 33 | Write-Verbose "PSake.build_success: $($psake.build_success)" -Verbose 34 | if (-not $psake.build_success) { exit 1 } 35 | 36 | - 37 | branches: 38 | only: 39 | - master 40 | 41 | test_script: 42 | - ps: | 43 | Invoke-PSake -BuildFile .\Build.PSake.ps1 -TaskList Publish 44 | Write-Verbose "PSake.build_success: $($psake.build_success)" -Verbose 45 | if (-not $psake.build_success) { exit 1 } 46 | -------------------------------------------------------------------------------- /en-US/XmlEx.Resources.psd1: -------------------------------------------------------------------------------- 1 | # en-US 2 | ConvertFrom-StringData @' 3 | CreatingDocument = Creating XmlEx document. 4 | SettingDocumentNamespace = Setting document namespace to '{0}'. 5 | SettingDocumentNamespaceWithPrefix = Setting document namespace '{0}' with prefix '{1}'. 6 | SettingDefaultDocumentNamespace = Setting default document namespace '{0}'. 7 | AddingElement = Adding element '{0}' to element '{1}'. 8 | AddingAttribute = Adding attribute '{0}' to element '{1}'. 9 | AddingTextNode = Adding text node to element '{0}'. 10 | AddingComment = Adding comment to element '{0}'. 11 | AddingDocumentNamespace = Adding document namespace '{0}'. 12 | FinalizingDocument = Finalizing XmlEx document. 13 | 14 | ProcessingDocument = Process Xml document '{0}'. 15 | AppendingXmlElementPath = Appending Xml element/path '{0}'. 16 | AppendingXmlAttributePath = Appending attribute '{0}'. 17 | AppendingXmlTextNodePath = Appending text node '{0}'. 18 | SavingDocument = Saving Xml document '{0}'. 19 | 20 | XmlExDocumentNotFoundError = XmlEx document not found/reference not set. 21 | XmlExElementNotFoundError = XmlEx element not found/reference not set. 22 | XmlExNamespaceMissingXmlElementError = Cannot add a 'XmlNamespace' to a document without a root element. 23 | XmlExDocumentMissingXmlElementError = Cannot add a 'XmlAttribute' to a document without a root element. 24 | XmlExInvalidCallOutsideScopeError = You cannot call '{0}' outside the '{1}' scope. 25 | XmlExInvalidCallWithinScopeError = You cannot call '{0}' from within the '{1}' scope. '{0}' must be nested within a '{2}' scope. 26 | CannotFindPathError = Cannot find path '{0}' because it does not exist. 27 | 28 | ShouldProcessOperationWarning = Performing operation "{0}" on Target "{1}". 29 | ShouldProcessWarning = Continue with this operation? 30 | '@; 31 | -------------------------------------------------------------------------------- /xml-tool-icon-53260.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iainbrighton/XmlEx/4a686180edcef207ef571cb7dbc57f6d8f12bd49/xml-tool-icon-53260.png --------------------------------------------------------------------------------