【问题标题】:Why is the XML created using powershell scripting not in the right format?为什么使用 powershell 脚本创建的 XML 格式不正确?
【发布时间】:2022-01-25 06:10:49
【问题描述】:

我正在执行一个 PS 脚本来读取 xml 的内容,更新一些标签值并将内容存储到多个 xml 文件中。我能够实现所有这些,但是创建的 xml 文件没有被传递到的消息队列正确读取。但是当我打开它并单击保存而不对数据进行任何更改时,相同的 xml 文件在队列中工作。我比较了两个文件 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 文件:每个 emailID 来自 Performancetest003-010@ymail.com 的 5 个事务文件。但是,在我打开并单击保存(没有数据更改)之前,消息队列都没有识别到​​它。

【问题讨论】:

  • 您是用什么打开和保存 XML 文件的?这可能是文本编码的问题吗? (UTF-8 vs ASCII等)当你说“消息队列都没有识别它”时,错误消息是什么,队列技术是什么?
  • 我假设链接的副本回答了您的问题;如果没有,请告诉我们。
  • 在编辑器中重新保存文件时问题消失可能是由于编辑器保存文件没有 BOM。顺便说一句:如果您的 UTF-8 编码 XML 文件 没有 有 BOM 并且您使用 Get-ContentWindows PowerShell 中读取它,它可能是被误解(PowerShell (Core) 7+ 现在始终默认为 UTF-8)。要么使用-Encoding utf8,要么最好使用[xml] 类型的.Load() 方法来加载文件——参见this answer 的底部部分。
  • @mklement0 你是对的。编码是这里的问题。我在外部保存的所有文件都是 ANSI 格式,下游队列已成功读取。我从您将我重定向到的线程中尝试了几种不同的解决方案,但输出文件仍保存为 UTF-8。不确定如何转换为 XML ANSI 格式。这是我尝试过的事情(不成功) 1. ($loadXML = [xml]::new()).Load((Convert-Path "H:\CASH.XML")) 而不是 Get-Content 2。 $loadXML.Save("H:\"+$fileName) | Set-Content -LiteralPath "H:\$fileName" -Encoding Ascii #将输出文件格式更改为 ANSI
  • 说得太早了!在创建输出 XML 后使用下面的行,我能够生成一个 ANSI xml 文件。我确信有更优雅的方法可以解决这个问题,但这个方法可行:') Get-Content H:\$fileName | out-file -encoding ASCII H:\new_$fileName

标签: xml powershell character-encoding xml-parsing xml-declaration


【解决方案1】:

XML API 支持字符编码内置,并且如果给定的 XML 文档的声明在其 XML 声明中明确指定了编码(例如 &lt;?xml version="1.0" encoding="utf-8"?&gt; ),则在从并写入文件。

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

警告

  • 从 .NET 6.0 / PowerShell 7.2 开始,.Save() 方法意外地将具有显式 encoding 属性 "utf-8" 的 XML 文档保存到 UTF-8 文件中一个 BOM(字节顺序标记),这会导致一些 XML 使用者出现问题(即使它不应该这样做)。 解决方法是删除显式encoding 属性(将其设置为$null);详情请见this answer

您后来的反馈表明您正在寻找 ANSI 编码的输出 XML 文件,即 您的目标是从 UTF-转码输入 XML 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 属性您将创建 自相矛盾的 XML 文件;也就是说,文档声称在其 XML 声明中具有的编码与实际编码不匹配。这可能并不总是很重要(如果消费者也执行纯文本处理而不是正确的 XML 解析),但仅出于概念上的清晰性就应该避免这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 2011-09-06
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多