使用PHP编辑XML。只有第一次工作,为什么?

时间:2013-01-13 03:10:44

标签: php xml line uncheck

所以我的问题是,当我用一些PHP行编辑一个XML文件(下面)时,一切都是第一次工作,然后删除假行并在错误的地方创建新行。

这里是用于删除行的PHP脚本:

<?php
session_start(); 

// The file
$filePath = '/....../test/test.xml';

// Grab file into an array, by lines
$fileArr = file($filePath);

// Remove desired line
unset($fileArr[7]); // $fileArr[15] == line #16
unset($fileArr[16]); // idem
unset($fileArr[25]); // idem

//Put back with PHP5
file_put_contents($filePath, implode('', $fileArr ));

session_destroy(); 
?>

这里是编写新行的PHP脚本

<?php
session_start(); 

// The file
$filePath = '/....../test/test.xml';

// Grab file into an array, by lines
$fileArr = file($filePath);

//Change
$etichettaasse = "\t\t\t\t<string>\t14 gen</string>\n\r";
$medianord =  "\t\t\t\t<number>\t280\t</number>\n\r";
$mediasud =  "\t\t\t\t<number>\t280\t</number>\n\r";

// Replace line
$fileArr[11] = $etichettaasse;
$fileArr[19] = $medianord;
$fileArr[27] = $mediasud;

// Implode and save
file_put_contents($filePath, implode('', $fileArr ));

session_destroy(); 
?>

这里是原始 XML:

<chart>
<axis_category color='ffffff' skip='0' size='12' alpha='80' />
<axis_value color='ffffff' skip='10' size='12' show_min='false' min="80" max="130"  />
<chart_border top_thickness='1' bottom_thickness='1' left_thickness='1' right_thickness='1' />              
<chart_data>
    <row>
        <null/>
            <string>    3 dic</string>
            <string>    10 dic</string>
            <string>    17 dic</string>
            <string>    24 dic</string>
            <string>    31 dic</string>

    </row>
    <row>
        <string>Media Nord</string>
            <number>    102.72  </number>
            <number>    101.60  </number>
            <number>    101.85  </number>
            <number>    101.84  </number>
            <number>    101.84  </number>

    </row>
    <row>
        <string>Media Sud</string>
            <number>    102.28  </number>
            <number>    101.24  </number>
            <number>    101.70  </number>
            <number>    101.88  </number>
            <number>    101.88  </number>

    </row>
</chart_data>
</chart>

在第一轮PHP脚本之后,它会根据要求进行更新:

<chart>
<axis_category color='ffffff' skip='0' size='12' alpha='80' />
<axis_value color='ffffff' skip='10' size='12' show_min='false' min="80" max="130"  />
<chart_border top_thickness='1' bottom_thickness='1' left_thickness='1' right_thickness='1' />              
<chart_data>
    <row>
        <null/>
            <string>    10 dic</string>
            <string>    17 dic</string>
            <string>    24 dic</string>
            <string>    31 dic</string>
            <string>    14 gen</string>

    </row>
    <row>
        <string>Media Nord</string>
            <number>    101.60  </number>
            <number>    101.85  </number>
            <number>    101.84  </number>
            <number>    101.84  </number>
            <number>    280 </number>

    </row>
    <row>
        <string>Media Sud</string>
            <number>    101.24  </number>
            <number>    101.70  </number>
            <number>    101.88  </number>
            <number>    101.88  </number>
            <number>    280 </number>

    </row>
</chart_data>

第二轮PHP脚本之后:

<chart>
<axis_category color='ffffff' skip='0' size='12' alpha='80' />
<axis_value color='ffffff' skip='10' size='12' show_min='false' min="80" max="130"  />
<chart_border top_thickness='1' bottom_thickness='1' left_thickness='1' right_thickness='1' />              
<chart_data>
    <row>
        <null/>
            <string>    17 dic</string>
            <string>    24 dic</string>
            <string>    14 gen</string>
            <string>    14 gen</string>

    </row>
    <row>
        <string>Media Nord</string>
            <number>    101.60  </number>
            <number>    101.84  </number>
            <number>    280 </number>


            <number>    280 </number>

    <row>
        <string>Media Sud</string>
            <number>    101.24  </number>
            <number>    101.70  </number>
            <number>    280 </number>


    </row>
            <number>    280 </number>

如果我只有一个PHP文件而不是2个,我也很高兴,但我不知道该怎么做。

这是修改此XML文件的最佳方法,还是有其他方式?

请注意将从用户写入HTML的新行。

我有这个“开始”脚本,用于删除我要删除的内容。

你怎么看?

<?php
$file = '/...../test.xml';


$fp = fopen(file,"w"); // open it for WRITING ("w")

if (flock($fp, LOCK_EX)) {

    //do actions here
    $xml = file_get_contents($file);
    $sxe = simplexml_load_string($xml);

    echo '<pre>';

    // "delete the 1th string of row 1, etc."
    unset($sxe->chart_data->row[0]->string[0]);
    unset($sxe->chart_data->row[1]->number[0]);
    unset($sxe->chart_data->row[2]->number[0]);

    $sxe->chart_data->row[0]->addChild('string', 'test');
    $sxe->chart_data->row[1]->addChild('number', '999');
    $sxe->chart_data->row[2]->addChild('number', '9999');

    file_put_contents($file, $sxe->asXML());


    // unlock the file
    flock($fp, LOCK_UN);

} else {

    // flock() returned false, no lock obtained
    print "Could not lock $file!\n";
}

?>

2 个答案:

答案 0 :(得分:2)

问题是,当您unset()数组成员时,您更改了行号。这很容易证明:

$origfile = array(
    "line1\n",
    "line2\n",
    "line3\n",
);

unset($file[1]); // delete line 2

$round1file = implode('', $file); // "write the file"

结果是两行文件,而不是三行文件!

line1
line3

因此,当您再次阅读时,您的数组将如下所示:

$round1file = array("line1\n","line3\n");

如果再次删除第2行,您显然会留下array("line1\n")

立即解决方案是用空行替换行而不是取消数组成员,即$fileArr[7] = "\n"而不是unset($fileArr[7])

但是,你正在做的事情是完全疯了。这是一个XML文件,所以你需要用XML库解析和编写它,或者我保证你你最终会得到它迟早无效的XML !此外,您无法安全地写入多个进程可能正在使用的文件 - 您需要使用某种文件锁定或适当的数据库。

对于文件锁定,您可以使用这样的一对函数:

function file_get_contents_locked($filename)
{
    $fp = fopen($filename, 'rb');
    if ($fp===FALSE) {
        throw new RuntimeException("Could not open file '{$filename}'");
    }
    if (flock($fp, LOCK_SH)) {
        $data = stream_get_contents($fp);
        flock($fp, LOCK_UN);
        fclose($fp);
        return $data;
    } else {
            fclose($fp);
        throw new RuntimeException("Could not acquire lock on file '{$filename}'");
    }
}


function file_put_contents_locked($filename, $data)
{
    return file_put_contents($filename, $data, LOCK_EX);
}

或者如果您使用的是某种类型的重命名是原子的,您可以写入临时文件并重命名旧文件而不是使用锁定。 (在这种情况下你不需要锁定,因为只要你用这个方法写,文件永远不会半读或半写。)

function write_atomic($fullfilename, $data) {
    $tmpname = tempnam(dirname($fullfilename), 'write_atomic-');
    if (FALSE!==file_put_contents($tmpname, $data)) {
        rename($tmpname, $fillfilename);
    }
    unlink($tmpname);
}

对于XML操作,两个简单的选项是SimpleXML,它更简单但功能更弱,而DOMDocument更复杂但功能更强大。 (您也可以使用XMLReader和XMLWriter,但这些使用起来要困难得多,而且速度要慢得多 - 只有在您无法将整个XML文件同时放入内存时才需要它们。)

这是一个让你入门的例子。查看链接的文档以获取更多详细信息:

function delete_xml_stuff($filename)
{
    $xml = file_get_contents_locked($filename);
    $sxe = simplexml_load_string($xml);
    // e.g., "delete the 2th string of row 1"
    unset($sxe->chart_data->row[0]->string[1]);
    file_put_contents_locked($filename, $sxe->asXML());

    // if you have more complex criteria, use DOMDocument:

    $d = new DOMDocument();
    $d->loadXML($xml);
    $xp = new DOMXPath($d);
    $results = $xp->query('//chart_data/row[2]/*[3]');
    if ($results->length) {
        $row2column3 = $results->item(0);
        $row2column3->parentNode->removeChild($row2column3);
    }
    file_put_contents_locked($d->saveXML());
}

答案 1 :(得分:1)

在使用xml时,您应该考虑使用像DOMDocument / XPath或simplexml这样的xml库。无论是否修复此错误,您都将达到XML处理您认为非常混乱的方式。

例如,查看SimpleXML和页面上的示例。