1

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

如何以可读格式创建输出 xml 文件?不确定当我在 xml 文件上单击“保存”时会发生什么变化。请帮忙。

输入 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 文件:来自 Performancetest 003-010 @ymail.com的每个 emailID 的 5 个事务文件。但是,直到我打开并单击保存(没有数据更改)之前,消息队列都没有识别到​​它。

4

1 回答 1

1

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

因此,读取和写入 XML 文件可靠方法是使用专用的 XML API (在本例中为[xml]( System.Xml.XmlDocument)类型.Load().Save()方法),而不是使用纯文本处理 cmdlet,例如Get-ContentSet-Content/ Out-File

警告

  • 从 .NET 6.0 / PowerShell 7.2 开始,该.Save()方法意外地将具有显式encoding属性的 XML 文档保存到带有 BOM"utf-8" (字节顺序标记)的 UTF-8 文件中,这会导致一些 XML 使用者出现问题(即使它不应该t)。解决方法是删除expiicitencoding属性(将其设置为$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>

注意

  • 不要尝试通过纯文本处理来执行转码,例如使用 and 的组合Get-Content,因为在输入 XML 中Set-Content有明确的属性,您将创建自相矛盾的XML 文件;也就是说,文档声称在其 XML 声明中具有的编码与实际编码不匹配。这可能并不总是很重要(如果消费者也执行纯文本处理而不是正确的 XML 解析),但应该避免仅出于概念清晰性的考虑。encoding
于 2021-12-27T13:58:56.660 回答