为什么使用 powershell 脚本创建的 XML 格式不正确?

Why is the XML created using powershell scripting not in the right format?

我正在执行 PS 脚本来读取 xml 的内容,更新一些标签值并将内容存储到多个 xml 文件中。我能够实现所有这些,但是创建的 xml 文件没有被传递到的消息队列正确读取。但是当我打开它并单击保存而不对数据进行任何更改时,相同的 xml 文件在队列中工作。我比较了这两个文件 1 - 创建后和 2 - 在我打开它并单击保存后它们是相同的! 我这辈子都弄不清楚哪里出了问题以及如何解决它。

如何创建可读格式的输出 xml 文件?当我在 xml 文件上单击 'Save' 时,不确定会发生什么变化。请帮忙。

输入CASH.XML:

<?xml version="1.0" encoding="UTF-8"?>
<ns:POSTransaction xmlns:ns="http://schema.xyz.com/Commerce/Customer/Transaction/v1">
<ns:tranHeader>
<ns:transactionId>96846836238236142669</ns:transactionId>
<ns:businessDateTime>2021-12-25T01:10:00</ns:businessDateTime>
<ns:emailId>Perftesting002@ymail.com</ns:emailId>
</ns:tranHeader>
</ns:POSTransaction>

PS:

$log="H:\logs.txt"
[xml]$loadXML = Get-Content "H:\Q_This\CASH.XML"

try
{
   $tranID = $loadXML.POSTransaction.tranHeader.transactionId.substring(17,3)
   $tranIntID = [int]$tranID   
   $tranc = $loadXML.POSTransaction.tranHeader.transactionId.substring(0,17)    
   $uname = $loadXML.POSTransaction.tranHeader.emailId.substring(0,11)
   $mailcnt = [int]$loadXML.POSTransaction.tranHeader.emailId.substring(11,3)
   $mailend = $loadXML.POSTransaction.tranHeader.emailId.Split("@")[1]

   for ($mailcnt; $mailcnt -lt 10; $mailcnt++)
   {    
        for ([int]$i =1; $i -le 5; $i++)
        {
        $mailupd = ([string]($mailcnt+1)).PadLeft(3,'0')
        $tranIntID = $tranIntID+1
        $loadXML.POSTransaction.tranHeader.transactionId = $tranc+[string]$tranIntID
        $loadXML.POSTransaction.tranHeader.emailId = $uname+$mailupd+'@'+$mailend
        $fileName = "CASH_"+$tranIntID+"_"+$mailupd+".XML"
        $loadXML.Save("H:\Q_This\"+$fileName)
        }
   }
}
catch
{
    Write-Host $_.Exception.Message
    Add-content $log -value ([string](Get-Date) + ' ' +$_.Exception.Message)    
}

以上代码创建了 40 个输出 xml 文件:来自 Performancetest003-010@ymail.com 的每个电子邮件 ID 有 5 个交易文件。但是,在我打开并单击保存(没有数据更改)之前,消息队列识别了其中的 none。

XML API 支持字符编码 内置 ,并且如果给定的 XML 文档的声明明确指定编码它的 XML 声明(例如 <?xml version="1.0" encoding="utf-8"?> ),在读取和写入文件时都遵守编码。

因此,读取和写入 XML 文件的 稳健 方法是使用 专用 XML API - [xml] (System.Xml.XmlDocument) type's .Load() and .Save() methods in this case - rather than plain-text processing cmdlets such as Get-Content and Set-Content / Out-File.

警告:

  • 自 .NET 6.0/PowerShell 7.2 起,.Save() 方法意外地保存 XML 文档,其中包含显式 [= "utf-8" 的 23=] 属性到具有 BOM(字节顺序标记)的 UTF-8 文件 ,这会导致一些问题 XML 消费者(即使它不应该)。 解决方法是 删除 expiicit encoding 属性(将其设置为 $null);有关详细信息,请参阅

您后来的反馈表明您正在寻找 ANSI 编码的输出 XML 文件,即 您的目标是 转码 将输入 XML 从 UTF-8 转为 ANSI.

以下是此类转码的简化、独立示例。 它假定您系统的活动 ANSI 代码页是 Windows-1252.

# In- and output files.
# IMPORTANT:
#   Always use *full, file-system-native paths* when calling .NET methods.
$inFile =   Join-Path $PWD.ProviderPath in.xml
$outFile =  Join-Path $PWD.ProviderPath out.xml

# Create a UTF-8-encoded sample input file,
# for simplicity with plain-text processing.
# Note the non-ASCII character in the element text ('ä')
'<?xml version="1.0" encoding="utf-8"?><foo>bär</foo>' | Set-Content -Encoding utf8 $inFile

# Read the file using the XML-processing API provided via the [xml] type.
$xml = [xml]::new()
$xml.Load($inFile)

# Now change the character-encoding attribute to the desired new encoding.
# An XML declaration - if present - is always the *first child node* 
# of the [xml] instance.
$xml.ChildNodes[0].encoding = 'windows-1252'

# Save the document.
# The .Save() method will automatically respect the specified encoding.
$xml.Save($outFile)

要验证输出文件是否正确 Windows-1252 编码,请使用以下命令:

  • PowerShell(核心)7+
# PowerShell (Core) defaults to UTF-8 in the absence of a BOM.
Get-Content -Encoding 1252 $outFile
  • Windows PowerShell
# Windows PowerShell *defaults* to the 
# system's active ANSI code page in the absence of a BOM.
Get-Content $outFile

您应该会看到以下输出 - 请注意非 ASCII 字符的正确呈现,ä:

<?xml version="1.0" encoding="windows-1252"?>
<foo>bär</foo>

:

  • 不要不要尝试通过纯文本处理执行转码,例如使用Get-ContentSet-Content 的组合,因为在输入 XML 中使用明确的 encoding 属性,您将创建 self-自相矛盾 XML 个文件;也就是说,文档在其 XML 声明中声明的编码将与实际编码不匹配。这可能并不总是很重要(如果消费者也执行纯文本处理而不是正确的 XML 解析),但应该避免仅仅为了概念清晰。