多次解析 XML 文件并将结果合并在一起
Parsing XML file more than once and merging the results together
我有一个子程序解析了2XMLs,一个是原始日志数据,一个是过滤器。我想从 log.xml 中删除在其中一个过滤器中找不到的所有内容。
这是我的日志文件的示例:
<log>
<message>
<type>warning</type>
<from>cody</from>
<content>cant use XML::Merge</content>
</message>
<message>
<type>error</type>
<from>cody</from>
<content>some text here</content>
</message>
<message>
<type>warning</type>
<from>charlie</from>
<content>ruff</content>
</message>
<message>
<type>error</type>
<from>cody</from>
<content>an error</content>
</message>
</log>
filter.xml 看起来像:
<filters>
<filter>
<type>warning</type>
<content>XML::Merge</content>
</filter>
<filter>
<type>error</type>
</filter>
</filters>
这应该会导致包含内容 "XML::Merge" 的所有警告和所有错误都被保留。我的尝试是使用第一个过滤器进行第一次传递,这会导致所有其他消息节点被截断,因此我在生成的 XML 文件中没有发现任何错误。下一个过滤器然后切掉应该从第一个过滤器中保留下来的那些。这是我的代码,如果 filter.xml 中只有一个过滤器,它运行良好。
sub include {
my $filterParser = XML::LibXML->new->parse_file($filterXML);
my $logParser = XML::LibXML->new->parse_file($xml);
foreach my $filter ( $filterParser->findnodes('/filters/filter') ) {
foreach my $msg ( $logParser->findnodes('/log/message') ) {
foreach my $msgNode ($msg->childNodes) {
foreach my $filterNode ($filter->childNodes) {
if ($msgNode->localName eq $filterNode->localName) {
my $m = $msgNode->textContent;
my $f = $filterNode->textContent;
if (index($m, $f) == -1) {
$msg->parentNode->removeChild($msg);
}
}
}
}
}
}
$logParser->toFile($xml);
}
我明白为什么它会输出一个包含多个过滤器的空白文档,但需要帮助将第一个通道保存在某处,然后使用原始 XML 对第二个过滤器进行通道,依此类推上,直到没有过滤器,然后将所有内容合并为一个 XML,没有重复的消息。
我想这个问题的标题可能不太好,但希望这个问题和答案有一天能对其他人有所帮助。无论如何,我已经用一些蛮力实现了我的目标......我最终为每个过滤器做了一个传递,并将我想要保留的节点添加到列表中(我需要一个标志,因为一些过滤器有多个单一的标准).在对所有消息处理完所有过滤器后,我循环遍历 log.xml 并查找保存在我的列表中的每个节点。如果 log.xml 中的节点与列表中的任何节点都不匹配,我将其从树中删除。
sub include {
my $filterParser = XML::LibXML->new->parse_file($filterXML);
my $logParser = XML::LibXML->new->parse_file($xml);
my $remove = true;
my @nodes;
foreach my $msg ( $logParser->findnodes('/TdsMainLog/message') ) {
foreach my $filter ( $filterParser->findnodes('/filters/filter') ) {
foreach my $msgNode ($msg->childNodes) {
foreach my $filterNode ($filter->childNodes) {
if ($msgNode->localName eq $filterNode->localName) {
my $m = $msgNode->textContent;
my $f = $filterNode->textContent;
if ( index($m, $f) != -1 ) {
#mark for keeping
$remove = false;
}
else { $remove = true; } #else unmark
}
}
}
if ($remove eq false) { push (@nodes, $msg); }
$remove = true;
}
}
foreach my $msg ( $logParser->findnodes('/TdsMainLog/message') ) {
$remove = true;
foreach my $node (@nodes) {
if ($msg->isSameNode($node)) {
$remove = false;
}
}
if ($remove eq true) { $msg->parentNode->removeChild($msg); }
}
$logParser->toFile($xml);
}
我有一个子程序解析了2XMLs,一个是原始日志数据,一个是过滤器。我想从 log.xml 中删除在其中一个过滤器中找不到的所有内容。
这是我的日志文件的示例:
<log>
<message>
<type>warning</type>
<from>cody</from>
<content>cant use XML::Merge</content>
</message>
<message>
<type>error</type>
<from>cody</from>
<content>some text here</content>
</message>
<message>
<type>warning</type>
<from>charlie</from>
<content>ruff</content>
</message>
<message>
<type>error</type>
<from>cody</from>
<content>an error</content>
</message>
</log>
filter.xml 看起来像:
<filters>
<filter>
<type>warning</type>
<content>XML::Merge</content>
</filter>
<filter>
<type>error</type>
</filter>
</filters>
这应该会导致包含内容 "XML::Merge" 的所有警告和所有错误都被保留。我的尝试是使用第一个过滤器进行第一次传递,这会导致所有其他消息节点被截断,因此我在生成的 XML 文件中没有发现任何错误。下一个过滤器然后切掉应该从第一个过滤器中保留下来的那些。这是我的代码,如果 filter.xml 中只有一个过滤器,它运行良好。
sub include {
my $filterParser = XML::LibXML->new->parse_file($filterXML);
my $logParser = XML::LibXML->new->parse_file($xml);
foreach my $filter ( $filterParser->findnodes('/filters/filter') ) {
foreach my $msg ( $logParser->findnodes('/log/message') ) {
foreach my $msgNode ($msg->childNodes) {
foreach my $filterNode ($filter->childNodes) {
if ($msgNode->localName eq $filterNode->localName) {
my $m = $msgNode->textContent;
my $f = $filterNode->textContent;
if (index($m, $f) == -1) {
$msg->parentNode->removeChild($msg);
}
}
}
}
}
}
$logParser->toFile($xml);
}
我明白为什么它会输出一个包含多个过滤器的空白文档,但需要帮助将第一个通道保存在某处,然后使用原始 XML 对第二个过滤器进行通道,依此类推上,直到没有过滤器,然后将所有内容合并为一个 XML,没有重复的消息。
我想这个问题的标题可能不太好,但希望这个问题和答案有一天能对其他人有所帮助。无论如何,我已经用一些蛮力实现了我的目标......我最终为每个过滤器做了一个传递,并将我想要保留的节点添加到列表中(我需要一个标志,因为一些过滤器有多个单一的标准).在对所有消息处理完所有过滤器后,我循环遍历 log.xml 并查找保存在我的列表中的每个节点。如果 log.xml 中的节点与列表中的任何节点都不匹配,我将其从树中删除。
sub include {
my $filterParser = XML::LibXML->new->parse_file($filterXML);
my $logParser = XML::LibXML->new->parse_file($xml);
my $remove = true;
my @nodes;
foreach my $msg ( $logParser->findnodes('/TdsMainLog/message') ) {
foreach my $filter ( $filterParser->findnodes('/filters/filter') ) {
foreach my $msgNode ($msg->childNodes) {
foreach my $filterNode ($filter->childNodes) {
if ($msgNode->localName eq $filterNode->localName) {
my $m = $msgNode->textContent;
my $f = $filterNode->textContent;
if ( index($m, $f) != -1 ) {
#mark for keeping
$remove = false;
}
else { $remove = true; } #else unmark
}
}
}
if ($remove eq false) { push (@nodes, $msg); }
$remove = true;
}
}
foreach my $msg ( $logParser->findnodes('/TdsMainLog/message') ) {
$remove = true;
foreach my $node (@nodes) {
if ($msg->isSameNode($node)) {
$remove = false;
}
}
if ($remove eq true) { $msg->parentNode->removeChild($msg); }
}
$logParser->toFile($xml);
}