0

したがって、私の問題は、いくつかの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スクリプトの2回目のラウンドの後:

<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つではなく1つしかない場合も嬉しいですが、その方法がわかりません。

これはこの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";
}

?>
4

2 に答える 2

2

問題はunset()、配列メンバーの行番号を変更する場合です。これは簡単に実証できます。

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

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

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

結果は、3行のファイルではなく、2行のファイルになります。

line1
line3

したがって、もう一度読み込むと、配列は次のようになります。

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

2行目をもう一度削除すると、明らかに残りますarray("line1\n")

当面の解決策は、配列メンバーを設定解除するのではなく、行を空白行に置き換えることです。つまり、.$fileArr[7] = "\n"unset($fileArr[7])

しかし、あなたがしていることは完全に正気ではありません。これは 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);
}

または、名前変更がアトミックな種類の *nix を使用している場合は、一時ファイルに書き込み、ロックを使用する代わりに古いファイルに名前を変更できます。(この場合、このメソッドを使用して書き込みを行う限り、ファイルが半分読み取られたり半分書き込まれたりすることはないため、ロックは必要ありません。)

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

XML 操作の 2 つの簡単なオプションは、単純ですが強力ではない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());
}
于 2013-01-13T03:59:27.177 に答える
1

xml を使用する場合は、DOMDocument/XPath や simplexml などの xml ライブラリの使用を検討する必要があります。このバグを修正するかどうかに関係なく、XML の処理が非常に面倒になるポイントに到達することになります。

たとえば、SimpleXMLとページの例を見てください。

于 2013-01-13T03:32:16.773 に答える