使用 powershell 脚本分析 XML 文件
Analyse XML file with powershell script
我有一个 xml 日志文件。该文件如下所示:
<Transaction name='0' id='1'>
<Response>Warning</Response>
<Statistic mode='Element'>
<Information>0</Information>
<Warning>0</Warning>
<Error>0</Error>
</Statistic>
<Messages>
<Message state='Warning'>Personal-Nr.: 12345, Tom Test</Message>
<Message state='Warning'>This is a warning message 1</Message>
<Message state='Warning'>This is a warning message 2</Message>
<Message state='Warning'>This is a warning message 3</Message>
<Message state='Warning'>This is a warning message 4</Message>
</Messages>
</Transaction>
此模式重复约 900 次,有时消息或多或少。现在我只想获取 <Response>Error</Response>
发生的所有交易。
所以我在 Powershell 中编写了这段代码:
## parsing xml file and opening inner node
Select-Xml -Path C:\Users\user\path\path\file.xml -XPath '/Paths/Task/Transaction' | ForEach-Object { $_.Node.InnerXML }
## looping through Response set with include="Error"
$_.Node.InnerXML | Where-Object Response -eq 'Error' | ForEach-Object { $_.Messages }
echo $_.Messages
但我得到的唯一数据是所有交易,无论响应是 Warning
还是 Error
。更进一步,即使我只留下 Select-Xml
行并删除其余部分也没有关系。结果总是一样的。我总是得到所有的回应。
所以我的问题是:
如何只获取响应为 Error
的交易?
奖金问题:是否有可能只将每个 Error
交易的第一条消息行作为输出?这样我就有了错误交易中所有 Personal-Nr
的列表?
非常感谢
您发布的语句目前是完全独立的——第一个输出所有交易节点的文本编码,第二个和第三个只是什么都不做 ,因为那时 $_
不再有分配给它的值。
要正确“连接”它们,您必须将过滤逻辑放在第一个 ForEach-Object
块中,例如:
Select-Xml ... |ForEach-Object {
if($_.Node.Response -eq 'Error'){ $_.Messages }
}
... 或将每个步骤的输出存储在临时变量中,例如:
$allTransactions = Select-Xml ... -XPath '//Transaction'
$allTransactions |ForEach-Object {
if($_.Node.Response -eq 'Error'){ $_.Messages }
}
我应该指出 ForEach-Object { if(...){ $_ } }
有点像 anti-pattern 除非您的代码有更复杂的副作用 - 更惯用的解决方案是调用 Where-Object
cmdlet 来过滤 Select-Xml
:
的输出
$allTransactions |Where-Object {
$_.Node.Response -eq 'Error'
} |ForEach-Object Messages
虽然这些建议可能会解决您的问题,但我强烈建议不要那样做 - XPath 比您的更强大目前正在使用它:)
How do I get only get the transactions where the Response is "Error"?
我建议通过使用更 准确 XPath 表达式和 Select-Xml
来简化您的代码 - 一个可以准确查找您想要的内容的表达式:
Select-Xml -Path C:\Users\user\path\path\file.xml -XPath '/Paths/Task/Transaction[Response = "Error"]'
Is there a possibility to just have the first message line of each "Error" transaction as a output? So that I have a list of all the "Personal-Nr" that were in an error transaction?
没问题!
再次最简单的方法是修改 XPath 表达式,这次只解析符合条件的 <Transaction>
下的 first <Message>
节点以上:
# beware that index selectors in XPath start at 1, not 0
//Transaction[Response = "Warning"]/Messages/Message[1]
但这还不是全部! XPath 有几个有用的函数 - 所以我们可以 更深入 并让 XPath
也为我们提取和解码消息文本!
//Transaction[Response = "Warning"]/Messages/Message[1]/text()
这将导致 Select-Xml
到 return 由 XmlText
个实例组成的节点集,您可以直接将其转换为字符串以获取原始字符串内容。
将它与 Select-Xml
放回一起,你最终会得到这样的结果:
$filePath = 'C:\Users\user\path\path\file.xml'
$xPath = '//Transaction[Response = "Warning"]/Messages/Message[1]/text()'
$messages = Select-Xml -Path $filePath -XPath $xPath |ForEach-Object ToString
$messages
我有一个 xml 日志文件。该文件如下所示:
<Transaction name='0' id='1'>
<Response>Warning</Response>
<Statistic mode='Element'>
<Information>0</Information>
<Warning>0</Warning>
<Error>0</Error>
</Statistic>
<Messages>
<Message state='Warning'>Personal-Nr.: 12345, Tom Test</Message>
<Message state='Warning'>This is a warning message 1</Message>
<Message state='Warning'>This is a warning message 2</Message>
<Message state='Warning'>This is a warning message 3</Message>
<Message state='Warning'>This is a warning message 4</Message>
</Messages>
</Transaction>
此模式重复约 900 次,有时消息或多或少。现在我只想获取 <Response>Error</Response>
发生的所有交易。
所以我在 Powershell 中编写了这段代码:
## parsing xml file and opening inner node
Select-Xml -Path C:\Users\user\path\path\file.xml -XPath '/Paths/Task/Transaction' | ForEach-Object { $_.Node.InnerXML }
## looping through Response set with include="Error"
$_.Node.InnerXML | Where-Object Response -eq 'Error' | ForEach-Object { $_.Messages }
echo $_.Messages
但我得到的唯一数据是所有交易,无论响应是 Warning
还是 Error
。更进一步,即使我只留下 Select-Xml
行并删除其余部分也没有关系。结果总是一样的。我总是得到所有的回应。
所以我的问题是:
如何只获取响应为 Error
的交易?
奖金问题:是否有可能只将每个 Error
交易的第一条消息行作为输出?这样我就有了错误交易中所有 Personal-Nr
的列表?
非常感谢
您发布的语句目前是完全独立的——第一个输出所有交易节点的文本编码,第二个和第三个只是什么都不做 ,因为那时 $_
不再有分配给它的值。
要正确“连接”它们,您必须将过滤逻辑放在第一个 ForEach-Object
块中,例如:
Select-Xml ... |ForEach-Object {
if($_.Node.Response -eq 'Error'){ $_.Messages }
}
... 或将每个步骤的输出存储在临时变量中,例如:
$allTransactions = Select-Xml ... -XPath '//Transaction'
$allTransactions |ForEach-Object {
if($_.Node.Response -eq 'Error'){ $_.Messages }
}
我应该指出 ForEach-Object { if(...){ $_ } }
有点像 anti-pattern 除非您的代码有更复杂的副作用 - 更惯用的解决方案是调用 Where-Object
cmdlet 来过滤 Select-Xml
:
$allTransactions |Where-Object {
$_.Node.Response -eq 'Error'
} |ForEach-Object Messages
虽然这些建议可能会解决您的问题,但我强烈建议不要那样做 - XPath 比您的更强大目前正在使用它:)
How do I get only get the transactions where the Response is "Error"?
我建议通过使用更 准确 XPath 表达式和 Select-Xml
来简化您的代码 - 一个可以准确查找您想要的内容的表达式:
Select-Xml -Path C:\Users\user\path\path\file.xml -XPath '/Paths/Task/Transaction[Response = "Error"]'
Is there a possibility to just have the first message line of each "Error" transaction as a output? So that I have a list of all the "Personal-Nr" that were in an error transaction?
没问题!
再次最简单的方法是修改 XPath 表达式,这次只解析符合条件的 <Transaction>
下的 first <Message>
节点以上:
# beware that index selectors in XPath start at 1, not 0
//Transaction[Response = "Warning"]/Messages/Message[1]
但这还不是全部! XPath 有几个有用的函数 - 所以我们可以 更深入 并让 XPath
也为我们提取和解码消息文本!
//Transaction[Response = "Warning"]/Messages/Message[1]/text()
这将导致 Select-Xml
到 return 由 XmlText
个实例组成的节点集,您可以直接将其转换为字符串以获取原始字符串内容。
将它与 Select-Xml
放回一起,你最终会得到这样的结果:
$filePath = 'C:\Users\user\path\path\file.xml'
$xPath = '//Transaction[Response = "Warning"]/Messages/Message[1]/text()'
$messages = Select-Xml -Path $filePath -XPath $xPath |ForEach-Object ToString
$messages