У меня есть xml-файл со следующей структурой.
<?xml version="1.0" encoding="utf-8"?> <products> <product> <nr>0</nr> <product_id>17856</product_id> <product_number>54586</product_number> <product_name>just an name</product_name> <product_url>product url</product_url> <price>66.3445</price> <description> bla die bla </description> <manufacturer>manu 1</manufacturer> <category>category 1</category> <stock>3</stock> <eancode></eancode> <date_added>2011-04-18 12:10:28</date_added> <image_front></image_front> <image_back></image_back> <vat_value>1.19</vat_value> </product> </products>
Файл xml содержит около 1000 продуктов.
То, что я хотел бы добиться, – это то, что когда я загружаю новый PHP-код xml, следует проверить, какие продукты изменили значения цены акции.
У меня есть рекурсивный метод массива, который показывает различия между файлами xml. Но он показывает только узлы xml, то есть, если запас был изменен, я вижу только содержимое в массиве.
Я использую следующую функцию, чтобы показать различия.
public function checkFile($file){ $xml = simplexml_load_file("./var/import/".$file); //nieuw $xml1 = $this->simplexml2array($xml); $xmls = simplexml_load_file("./var/import/oud/".$file); //oud $xml2 =$this->simplexml2array($xmls); $checkdiff = $this->arrayRecursiveDiff($xml2, $xml1); if ($checkdiff == NULL){ return false; }else{ return true; } } public function arrayRecursiveDiff($aArray1, $aArray2) { $aReturn = array(); foreach ($aArray1 as $mKey => $mValue) { if (array_key_exists($mKey, $aArray2)) { if (is_array($mValue)) { $aRecursiveDiff = $this->arrayRecursiveDiff($mValue, $aArray2[$mKey]); if (count($aRecursiveDiff)) { $aReturn[$mKey] = $aRecursiveDiff; } } else { if ($mValue != $aArray2[$mKey]) { $aReturn[$mKey] = $mValue; } } } else { $aReturn[$mKey] = $mValue; } } return $aReturn; } function simplexml2array($xml) { if (get_class($xml) == 'SimpleXMLElement') { $attributes = $xml->attributes(); foreach($attributes as $k=>$v) { if ($v) $a[$k] = (string) $v; } $x = $xml; $xml = get_object_vars($xml); } if (is_array($xml)) { if (count($xml) == 0) return (string) $x; // for CDATA foreach($xml as $key=>$value) { $r[$key] = $this->simplexml2array($value); } if (isset($a)) $r['@attributes'] = $a; // Attributes return $r; } return (string) $xml; }
может ли кто-нибудь помочь мне не показывать только поле разметки xml, а всю информацию о xml-продукте, которая была изменена.
Спасибо всем заранее.
Следующий код будет
Он работает путем итерации всех элементов продукта в старом XML, собирая их product_id, цены и значения запаса и собирает их в запрос XPath, который затем запускается против нового документа.
$oldXml = new DOMDocument; $oldXml->loadXml($old); $query = array(); foreach ($oldXml->getElementsByTagName('product') as $product) { $query[] = sprintf( '(product_id = %s and (price != "%s" or stock != "%s"))', $product->getElementsByTagName('product_id')->item(0)->nodeValue, $product->getElementsByTagName('price')->item(0)->nodeValue, $product->getElementsByTagName('stock')->item(0)->nodeValue ); } $query = implode('or', $query); $newXml = new DOMDocument; $newXml->loadXml($new); $xp = new DOMXPath($newXml); foreach ($xp->query(sprintf('/products/product[%s]', $query)) as $product) { echo $newXml->saveXml($product); }
$oldXml = simplexml_load_string($old); $query = array(); foreach ($oldXml->product as $product) { $query[] = sprintf( '(product_id = %s and (price != "%s" or stock != "%s"))', $product->product_id, $product->price, $product->stock ); } $query = implode('or', $query); $newXml = simplexml_load_string($new); foreach ($newXml->xpath(sprintf('/products/product[%s]', $query)) as $product) { echo $product->asXml(); }
Обратите внимание, что в этом документе не будут найдены какие-либо элементы продукта, которые были добавлены или удалены в новом документе. Вы не упомянули об этом в качестве требования в своем вопросе. Если вам это нужно, проще всего написать два дополнительных запроса. Один из них сравнивает элементы product_id с старым документом с новым документом, а другой – с новым документом до старого.
Попробуйте этот алгоритм сравнения:
function diff($old, $new){ foreach($old as $oindex => $ovalue){ $nkeys = array_keys($new, $ovalue); foreach($nkeys as $nindex){ $matrix[$oindex][$nindex] = isset($matrix[$oindex - 1][$nindex - 1]) ? $matrix[$oindex - 1][$nindex - 1] + 1 : 1; if($matrix[$oindex][$nindex] > $maxlen){ $maxlen = $matrix[$oindex][$nindex]; $omax = $oindex + 1 - $maxlen; $nmax = $nindex + 1 - $maxlen; } } } if($maxlen == 0) return array(array('d'=>$old, 'i'=>$new)); return array_merge( diff(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), array_slice($new, $nmax, $maxlen), diff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen))); } // Wrapper for diff - nicer output function htmlDiff($old, $new){ $diff = diff(explode(' ', $old), explode(' ', $new)); foreach($diff as $k){ if(is_array($k)) $ret .= (!empty($k['d'])?"<del>".implode(' ',$k['d'])."</del> ":''). (!empty($k['i'])?"<ins>".implode(' ',$k['i'])."</ins> ":''); else $ret .= $k . ' '; } return $ret; }
https://github.com/paulgb/simplediff/blob/5bfe1d2a8f967c7901ace50f04ac2d9308ed3169/simplediff.php