简体   繁体   English

使用 powershell 脚本分析 XML 文件

[英]Analyse XML file with powershell script

I've got a xml log file.我有一个 xml 日志文件。 The file looks like this:该文件如下所示:

<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>

This pattern repeats about 900 times Sometimes with more or less Messages.这种模式重复大约 900 次,有时会有更多或更少的消息。 Now I just want to get all the Transactions where the <Response>Error</Response> occurs.现在我只想获取发生<Response>Error</Response>的所有事务。

So I made this code in Powershell:所以我在 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

But the only data I get is all of the transactions, no matter if the response is Warning or Error .但我得到的唯一数据是所有交易,无论响应是Warning还是Error Even further, it doesn't even matter if I only leave the Select-Xml line and delete the rest.更进一步,我是否只留下Select-Xml行并删除其余行也没关系。 The result is always the same.结果总是一样的。 I always get ALL of the responses.我总是得到所有的回应。

So my question is: How do I get only get the transactions where the Response is Error ?所以我的问题是:我如何才能只获得 Response 为Error的交易?

Bonus question: Is there a possibility to just have the first message line of each Error transaction as a output?额外问题:是否有可能只将每个Error事务的第一条消息行作为输出? So that I have a list of all the Personal-Nr that were in an error transaction?这样我就有了一个错误交易中的所有Personal-Nr的列表?

Thanks a lot非常感谢

The statements you've posted are completely independent at the moment - the first one outputs the textual encoding of all the transactions nodes, and the second and third ones simply do nothing , because $_ no longer has a value assigned to it at that point.您发布的语句目前完全独立 - 第一个输出所有交易节点的文本编码,第二个和第三个根本不做任何事情,因为此时$_不再具有分配给它的值.

To properly "connect" them, you'd have to either place the filtering logic inside the first ForEach-Object block, eg.:要正确“连接”它们,您必须将过滤逻辑放在第一个ForEach-Object块中,例如:

Select-Xml ... |ForEach-Object {
  if($_.Node.Response -eq 'Error'){ $_.Messages }
}

... or store the output from each step in an interim variable, eg.: ...或将每个步骤的输出存储在临时变量中,例如:

$allTransactions = Select-Xml ... -XPath '//Transaction' 

$allTransactions |ForEach-Object {
  if($_.Node.Response -eq 'Error'){ $_.Messages }
}

I should point out that ForEach-Object { if(...){ $_ } } is a bit of an anti-pattern unless your code has more complicated side effects - the more idiomatic solution would be to invoke the Where-Object cmdlet to filter the output from Select-Xml :我应该指出ForEach-Object { if(...){ $_ } }有点反模式,除非您的代码具有更复杂的副作用 - 更惯用的解决方案是调用Where-Object cmdlet过滤来自Select-Xml的输出:

$allTransactions |Where-Object {
  $_.Node.Response -eq 'Error'
} |ForEach-Object Messages

While these suggestions might solve your problem, I strongly recommend not doing any of that - XPath is much more capable than what you're currently using it for :)虽然这些建议可能会解决您的问题,但我强烈建议您不要这样做- XPath 比您当前使用它的功能强大得多 :)


How do I get only get the transactions where the Response is "Error"?如何仅获取响应为“错误”的事务?

I'd suggest simplifying your code by using a more accurate XPath expression with Select-Xml - one that looks for exactly what you want:我建议通过使用带有Select-Xml的更准确的 XPath 表达式来简化您的代码——它可以准确地查找您想要的内容:

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?这样我就有了一个错误交易中所有“Personal-Nr”的列表?

Sure thing!确定的事!

Once again the easiest way is to modify the XPath expression, this time to only resolve the first <Message> node under a <Transaction> fitting the criteria above:再一次,最简单的方法是修改 XPath 表达式,这次只解析符合上述条件的<Transaction>下的第一个<Message>节点:

# beware that index selectors in XPath start at 1, not 0
//Transaction[Response = "Warning"]/Messages/Message[1]

But that's not all!但这还不是全部! XPath has several useful functions - so we can go one step deeper and have XPath extract and decode the message text for us too! XPath 有几个有用的功能——所以我们可以更深入一步,让XPath也为我们提取和解码消息文本!

//Transaction[Response = "Warning"]/Messages/Message[1]/text()

This will cause Select-Xml to return a node set consisting of XmlText instances which you can convert directly to strings to get the raw string content.这将导致Select-Xml返回一个由XmlText实例组成的节点集,您可以将其直接转换为字符串以获取原始字符串内容。

Putting it back together with Select-Xml , you end up with something like this:将其与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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM