2

所以我在PHP中使用simplexml和XML解析,但是我发现我需要解析的一些文件包含错误。当然,我可以手动编辑每个有问题的文件,但是大约 10000 多个文件,这将花费我很长时间。

好的,关于错误。当您尝试在浏览器中打开 XML 文件时,会显示以下消息:

属性错误的规范要求值

警告:simplexml_load_string():实体:第 2 行:解析器错误:在 ...

我找到了ff。标签正在触发错误(此处:Transport而不是Inspection):

<Public Transport Rules>
<PublicTransport id="0">
<Issued>null</Issued>
<Files>&lt;localfile&gt;
          &lt;location&gt;Citybus&lt;/location&gt;
          &lt;format&gt;Events&lt;/format&gt;
     &lt;/localfile&gt;
</Files>
</PublicTransport>
</Public Transport Rules>

显然,标签中的空格导致了这个问题。并且这些标签在文件中出现不止一次。

我认为它会simplexml根据它在浏览器中看到的内容进行解析(按面值),因此如果您的 XML 文件有问题,它将无法正常解析。我想通过读取源文件来进行 PHP 解析,也许从那里编辑文件。但它似乎fopens对您在浏览器页面中阅读的内容开放。

一段时间以来一直被这个问题困扰。任何意见,将不胜感激。

谢谢!

4

2 回答 2

2

如果您可以接受重命名包含空格的标记,那么 tidy 也是一个不错的选择,因为它也适用于 XML:

$xml = simplexml_load_string(
    tidy_repair_string($string, ['input-xml' => 1])
);

echo "SimpleXML::asXML():\n", $xml->asXML(), "\n\n";

它重命名标签并创建属性:

SimpleXML::asXML():
<?xml version="1.0"?>
<Public Transport="" Rules="">
<PublicTransport id="0">
<Issued>null</Issued>
<Files>&lt;localfile&gt; &lt;location&gt;Citybus&lt;/location&gt;
&lt;format&gt;Events&lt;/format&gt; &lt;/localfile&gt;</Files>
</PublicTransport>
</Public>

缩进等还有更多选项,这里有一个完整的例子:

<?php
/**
 * How to parse XML files with errors using Simplexml in PHP?
 *
 * @link http://stackoverflow.com/q/15620492/367456
 */

$string = '<?xml version="1.0" ?>
<Public Transport Rules>
    <PublicTransport id="0">
        <Issued>null</Issued>
        <Files>&lt;localfile&gt;
                  &lt;location&gt;Citybus&lt;/location&gt;
                  &lt;format&gt;Events&lt;/format&gt;
             &lt;/localfile&gt;
        </Files>
    </PublicTransport>
</Public Transport Rules>';

echo "Broken:\n", $string, "\n\n";

$fixed = tidy_repair_string($string, ['input-xml' => 1, 'output-xml' => 1, 'indent' => 1]);

echo "Fixed:\n", $fixed, "\n\n";


$xml = simplexml_load_string(tidy_repair_string($string, ['input-xml' => 1]));

echo "SimpleXML::asXML():\n", $xml->asXML(), "\n\n";

并输出:

Broken:
<?xml version="1.0" ?>
<Public Transport Rules>
    <PublicTransport id="0">
        <Issued>null</Issued>
        <Files>&lt;localfile&gt;
                  &lt;location&gt;Citybus&lt;/location&gt;
                  &lt;format&gt;Events&lt;/format&gt;
             &lt;/localfile&gt;
        </Files>
    </PublicTransport>
</Public Transport Rules>

Fixed:
<?xml version="1.0"?>
<Public Transport="" Rules="">
  <PublicTransport id="0">
    <Issued>null</Issued>
    <Files>&lt;localfile&gt;
    &lt;location&gt;Citybus&lt;/location&gt;
    &lt;format&gt;Events&lt;/format&gt; &lt;/localfile&gt;</Files>
  </PublicTransport>
</Public>

SimpleXML::asXML():
<?xml version="1.0"?>
<Public Transport="" Rules="">
<PublicTransport id="0">
<Issued>null</Issued>
<Files>&lt;localfile&gt; &lt;location&gt;Citybus&lt;/location&gt;
&lt;format&gt;Events&lt;/format&gt; &lt;/localfile&gt;</Files>
</PublicTransport>
</Public>
于 2013-11-02T13:34:06.877 回答
1

DOM 函数旨在处理无效标记,因此您可以尝试一下:

<?php

$string = '<?xml version="1.0" ?>
<Public Transport Rules>
    <PublicTransport id="0">
        <Issued>null</Issued>
        <Files>&lt;localfile&gt;
                  &lt;location&gt;Citybus&lt;/location&gt;
                  &lt;format&gt;Events&lt;/format&gt;
             &lt;/localfile&gt;
        </Files>
    </PublicTransport>
</Public>';

$dom = new DOMDocument;
libxml_use_internal_errors(TRUE);
$dom->loadHTML($string);
libxml_use_internal_errors(FALSE);
$dom->formatOutput = TRUE;

echo '::: Original XML :::' . PHP_EOL;
echo $string . PHP_EOL;
echo PHP_EOL;

echo '::: Fixed XML :::' . PHP_EOL;
if( version_compare(PHP_VERSION, '5.3.6', '>=') ){
    $body = $dom->documentElement->firstChild;
    if( $body->hasChildNodes() ){
        foreach($body->childNodes as $node){
            echo $dom->saveHTML($node);
        }
    }
}else{
    $body = $dom->getElementsByTagName('body')->item(0);
    if( $body->hasChildNodes() ){
        foreach($body->childNodes as $node){
            echo $dom->saveHTML($node);
        }
    }
}
echo PHP_EOL;

...打印这个:

::: Original XML :::
<?xml version="1.0" ?>
<Public Transport Rules>
    <PublicTransport id="0">
        <Issued>null</Issued>
        <Files>&lt;localfile&gt;
                  &lt;location&gt;Citybus&lt;/location&gt;
                  &lt;format&gt;Events&lt;/format&gt;
             &lt;/localfile&gt;
        </Files>
    </PublicTransport>
</Public>

::: Fixed XML :::
<public transport rules><publictransport id="0"><issued>null</issued><files>&lt;localfile&gt;
                  &lt;location&gt;Citybus&lt;/location&gt;
                  &lt;format&gt;Events&lt;/format&gt;
             &lt;/localfile&gt;
        </files></publictransport></public>

没有办法知道在这个过程中会丢失什么,但我们首先要处理无效数据。

无论如何,您始终可以使用 PHP自动编辑每个有问题的文件。您的文件可能不是 XML,但它们确实是字符串 ;-)

于 2013-03-25T17:14:31.167 回答