XML搜索和addChild

时间:2012-11-02 14:11:12

标签: php xml

这是我到目前为止所做的,我想将日期/时间日志添加到xml文件中。

   <?php

       // Load the XML file we want to write to
          $visitors  = simplexml_load_file("data.xml");

       // Set e-mail xml search
          $search_id = htmlentities($_POST['email']);
          $visitors = $visitors->xpath("visitor[email='$search_id']");

       // If we have a search result, email already exists in xml file
          if(isset($visitors[0])){
           $visitor = $visitors[0];
           $email = (string) $visitor->email;

           // ********** Need to add date/time for each visit here.
           // So, I guess I need to search for e-mail address, then append to it.
           // Help required here... and again below to confirm formatting for multiple
           // dates. 

          } else {
           $xml = simplexml_load_file("data.xml");
           $sxe = new SimpleXMLElement($xml->asXML());
           $search_id = preg_replace('/[^(\x20-\x7F)]*/','', $search_id);

            $visitor = $sxe->addChild("visitor");
            $visitor->addChild("email", $search_id);

            // ******** Not sure this is the correct xml formatting.  
               $date = $visitor->addChild('date');
               $date->addChild("email", date("Y-m-d H:i:s"));

           $sxe->asXML("data.xml");
          } // if(isset($visitors[0])){

       } // if(isset($data)){ ?>

生成

<?xml version="1.0" encoding="utf-8"?>
<visitors>
 <visitor>
  <email>jon.doe@aol.com</email>
  </visitor>
</visitors>

我想要做的是为每次访问添加一个日期日志(incementing / appending)。

所以结果会是(我不确定我的格式是否正确,这当然无关紧要)。不要担心PHP的日期/时间。

<?xml version="1.0" encoding="utf-8"?>
<visitors>
 <visitor>
  <email>jon.doe@aol.com</email>
  <date>2012-11-01 11:00:00</date>
  <date>2012-11-02 14:00:00</date>
  </visitor>
</visitors>

2 个答案:

答案 0 :(得分:3)

我认为你在这里走在正确的轨道上,主要的是你对asXML('data.xml')的调用是在你的ELSE块中,所以如果从头开始创建文件,它只会写入文件(即找不到search_id)。

我做了一些改动,主要是为了让它更容易理解。更多变化来了!:

<?php

// Load the XML file we want to write to
$xmlFile  = simplexml_load_file("data.xml");

// Set e-mail xml search
$search_id = 'jon.doe@aol.com';
$results = $xmlFile->xpath("visitor[email='$search_id']");

// If we have a search result, email already exists in xml file
if(isset($results[0]))
{
    $visitor = $results[0];
    $email = (string) $visitor->email;

    echo "Found Email: " . $email . "\n";
    echo "Date: " . $visitor->date . "\n";
    // ********** Need to add date/time for each visit here.
    // So, I guess I need to search for e-mail address, then append to it.
    // Help required here... and again below to confirm formatting for multiple
    // dates.
    echo "Adding new date";
    $visitor->addChild('date', date('Y-m-d H:i:s'));

    echo "New XML: " . $xmlFile->asXML();

    $xmlFile->asXML('data.xml');

} else {
    $sxe = new SimpleXMLElement($xmlFile->asXML());
    $search_id = preg_replace('/[^(\x20-\x7F)]*/','', $search_id);

    $visitor = $sxe->addChild("visitor");
    $visitor->addChild("email", $search_id);

    // ******** Not sure this is the correct xml formatting.
    $date = $visitor->addChild('date', date('Y-m-d H:i:s'));

    $sxe->asXML("data.xml");

}
?>

运行此脚本几次后,我得到了:

<?xml version="1.0"?>
<visitors>
        <visitor>
                <email>jon.doe@aol.com</email>
                <date>2012-11-03 02:13:28</date>
                <date>2012-11-03 02:20:20</date>
                <date>2012-11-03 02:22:07</date>
                <date>2012-11-03 02:22:10</date>
                <date>2012-11-03 02:22:13</date>
        </visitor>
</visitors>

我认为你想要的是什么?这有帮助吗?

修改

关于您是否提供正确的XML格式。我想没有专属的正确答案。我想说这种格式没问题,只要您记得在其自己的访客标记中分隔每个电子邮件地址/日期集。

要做到这一点,你可能想要这样的东西(未经测试):

$newVisitor = $xmlFile->addChild('visitor');
$newVisitor->addChild('email', $newEmail);
$newVisotor->addChild('date', $newDate);
$xmlFile->asXML('data.xml');

编辑2:

我过去使用的最后一件事是以下代码。它会更好地格式化XML,并且如果您在保存期间遇到任何问题(或者至少给您备份),它还可以防止原始XML文件的任何损坏。就个人而言,我试图养成使用这样的临时文件的习惯,只要我必须写入文件。

当然,只需添加此内容,然后将您的来电替换为:

  • $ xmlFile-&GT; asXML( 'data.xml中');
  • $ sxe-&GT; asXML( “data.xml中”);

使用:

  • writeXML('data.xml',$ xmlFile);
  • writeXML('data.xml',$ sxe);

它应该可以正常工作。

//Writes final version of the SimpleXML object to file.
//Includes writing to a temp file for safety.
//This way is safer because if the code crashes mid-write it won't garble the original file.
function writeXML($fileName, $xmlObject)
{
        //Sanity check before copy, prevent any visible errors:
        if (file_exists($fileName))
                copy($fileName, $fileName . '.backup');

        //Write to temp file first in-case something kills the write; don't want to corrupt the original.
        $tmpName = $fileName . '~$.' . microtime();
        $handle = fopen($tmpName, 'w');
        fwrite($handle, formatXML($xmlObject));
        fclose($handle);
        copy($tmpName, $fileName);
        unlink($tmpName);
}

//asXML does no indentation formatting, so we'll do it here instead. This is called by WriteXML so that we're writing formatted XML to file.
function formatXML($xmlObject)
{
        $dom = new DOMDocument('1.0');
        $dom->preserveWhiteSpace = false;
        $dom->formatOutput = true;
        $dom->loadXML($xmlObject->asXML());
        return $dom->saveXML();
}

答案 1 :(得分:1)

  

这是对@Geekmans answer

的补充

您的代码看起来并不太远。但是你可以大大改进它,这就是为什么在这里添加另一个答案(我通常会编辑@Geekmans答案,但它已经非常大了)。

改进的重点在于程序流程。如果找不到该电子邮件,则无需创建新的SimpleXMLElement,您只需创建一个新的<visitor>元素。然后添加<date>元素以及输出文件实际上对于两种情况都是相同的。这允许删除重复的代码:

// Specify the XML file we want to write to
$inFile = "data.xml";

// Set e-mail xml search and insert id
$search_id = 'jon.doe@aol.com';
$insert_id = preg_replace('/[^(\x20-\x7F)]*/', '', $search_id);

// Load the XML file we want to write to
$xmlFile = simplexml_load_file($inFile);
$results = $xmlFile->xpath("visitor[email='$search_id']");

// If we have a search result, email already exists in xml file
if ($results) {
    $visitor = $results[0];
    echo "Found Visitor: ", $visitor->email, "\n",
    "First Date: ", $visitor->date, "\n";
} else {
    echo "Adding new Visitor: ", $insert_id, "\n";
    $visitor = $xmlFile->addChild("visitor");
    $visitor->addChild("email", $insert_id);
}

echo "Adding new Date: ", $date = date('Y-m-d H:i:s'), "\n";
$visitor->addChild('date', $date);

echo "Changed XML: \n" . simplexml_pretty_print($xmlFile);
$xmlFile->asXML($inFile);


/**
 * @param SimpleXMLElement $simplexml
 * @link https://stackoverflow.com/a/798986/367456
 */
function simplexml_pretty_print(SimpleXMLElement $simplexml) {
    $dom                     = new DOMDocument();
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput       = true;
    $dom->loadXML($simplexml->asXML());
    return $dom->saveXML();
}

作为奖励,我添加了simplexml_pretty_print函数以更好的方式输出。

jon.doe@aol.com的输出:

Found Visitor: jon.doe@aol.com
First Date: 2012-11-01 11:00:00
Adding new Date: 2012-11-03 10:48:05
Changed XML: 
<?xml version="1.0" encoding="utf-8"?>
<visitors>
  <visitor>
    <email>jon.doe@aol.com</email>
    <date>2012-11-01 11:00:00</date>
    <date>2012-11-02 14:00:00</date>
    <date>2012-11-03 10:48:05</date>
  </visitor>
</visitors>

info@example.com的输出:

Adding new Visitor: info@example.com
Adding new Date: 2012-11-03 10:52:09
Changed XML: 
<?xml version="1.0" encoding="utf-8"?>
<visitors>
  <visitor>
    <email>jon.doe@aol.com</email>
    <date>2012-11-01 11:00:00</date>
    <date>2012-11-02 14:00:00</date>
  </visitor>
  <visitor>
    <email>info@example.com</email>
    <date>2012-11-03 10:52:09</date>
  </visitor>
</visitors>

提示:无论何时发现重复代码,通常都有一种方法可以用更简单的形式编写代码。