【问题标题】:Parser error : Opening and ending tag mismatch:解析器错误:开始和结束标签不匹配:
【发布时间】:2012-09-29 14:18:17
【问题描述】:

我在读取 XML 文件时遇到问题。如果您查看下面的 xml,您会看到元素 <fl> ?fl> 而不是 <fl></fl>。我收到错误开始和结束标签不匹配。

如何:

  1. XML 文件中存在错误,例如 <fl> ?fl> 而不是 <fl></fl>。如何在读取 xml 时忽略或修复此类错误,而不是使用它进行解析?
  2. 我只想阅读来自$_->{desc}->[0]->{en}->[0] 的内容,而不是来自<de><es><fl> 的内容。

现在我正在读取 XML 文件,例如:

package test::test6382_sunseekingeurope;
use strict;
use warnings;
use test;
use base qw/test/;
use URI::URL;
use XML::Simple;
use Data::Dumper;
use constant TASK_ID => 6382;
use constant CR_TYPE => '6382';
use constant IMAGE_PATH => "/home/testco/public_html/files/";#"images/";

sub new
{
my $class = shift;
my $self = $class->SUPER::new(CR_TYPE, TASK_ID);
bless $self, $class;

my $url = 'http://www.onbip.com/xml/sunseeking9.xml';

my $xml = $self->geturl('url'=>$url);
$self->extract($xml);
}

sub extract{
my $self = shift;
my $xmlfile = shift;
my $xml = new XML::Simple(ForceArray=>1,'KeyAttr' =>'image');
my $data = $xml->XMLin($xmlfile);

foreach(@{$data->{property}}){
    my $property = &makeScalar($_->ID->[0]);
    my $description = &makeScalar($_->{desc}->[0]->{en}->[0]);

XML:

<property>
<id>226887</id>
<desc>
 <en>
  Nice house in the center of Alhaurin de la Torre with walking distance to all amenities.
 </en>
 <es>
  Bonita casa mata en Alhaurin de la Torre con vistas a la montana, se puede acceder caminando al centro, colegios, etc.
 </es>
  <de>
    guter zustand, bezaubernde immobilie,
  </de>
  <fl>
    bon n acces par la route, partiellement meubl?a proximit?'?les, partiellement r?v
  ?fl>
</desc>
</property>

【问题讨论】:

  • 请下次使用正确的格式。
  • 您展示的代码不读取 XML,它只遍历 Perl 数据结构。我猜你正在使用一个模块来解析 XML,但你所拥有的显然不是 XML...

标签: perl xml-parsing mod-perl


【解决方案1】:

没有修复 XML 文件中的错误的通用方法。您所能做的就是将文件作为无效的 XML 拒绝。 The error handling documentation for XML::Simple 解释:

XML标准对不合规的问题非常明确 文件。解析任何单个元素时出错(例如 缺少结束标记)必须导致整个文档被拒绝。

基本问题是这样的:一旦您允许文件包含错误,它实际上可能包含任何内容。没有办法解析它。实在没有办法知道应该“纠正”什么。

如果无论出于何种原因,您的输入有一个非常具体的、可预测的错误,您可以在将其传递给XML::Simple 之前使用正则表达式来检测它。只要您知道一些特定的结束标签将使用??/ 而不是&lt;/,您就可以这样做:

my $xmlfile = shift;

my $xml = new XML::Simple(ForceArray=>1,'KeyAttr' =>'image');

#Try it to parse the file as is first.
my $data = eval { $xml->XMLin($xmlfile) };

#On error, try fixing.
if ($@)
{
    $xmlfile =~ s/\?\/?(desc|en|es|de|fl)>/<\/$1>/g;
    $data = eval { $xml->XMLin($xmlfile) };
    if ($@) 
    { 
        die "Failed to process the file even after attempting corrections: $@"; 
    }
}

以这种方式使用正则表达式有其危险——您依赖于特定格式的输入 XML。但是,通过首先尝试正常处理文件,至少可以最大限度地减少潜在的损坏。这样一来,您只会在文件无论如何都会失败的情况下做一些冒险的事情。

更新:向第二个 XMLIn() 调用添加了错误处理。

更新 2:我更新了正则表达式以仅匹配提问者所需的确切情况(在这种情况下,最好尽可能具体,以避免误报匹配)。

【讨论】:

  • 如何将$xmlfile中的?/fl>替换为 =~ s/\?(\w+>)/
  • 这个单一的正则表达式将修复?/fl&gt;?fl&gt;: $xmlfile =~ s/\?\/?(\w+&gt;)/&lt;\/$1/g; 但是,请注意:如果有两种以上的简单、可预测的错误,这个问题会变得非常混乱!您需要确保您确切地知道您的输入格式可能是什么,并且您已经处理了所有可能的情况。如果你不能这样做,那么你可能不应该为此使用正则表达式。
  • 我只有在 XML 中对这些元素有错误:->
  • @user1059749,错误是否都在结束标签中,或者它们也可能在开始标签中?如果它们可以在开始或结束标签中,那么将它们区分开来将是一个真正的问题。例如你不知道?es&gt; 是指&lt;es&gt; 还是&lt;/es&gt;
  • 只有结束标签。应该是: if ('?es>' OR '?/es>') 比 .
猜你喜欢
  • 2016-08-27
  • 2014-10-19
  • 1970-01-01
  • 2016-09-15
  • 1970-01-01
  • 2021-09-23
  • 2012-04-01
  • 2011-11-02
  • 1970-01-01
相关资源
最近更新 更多