我有一个具有以下结构的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个产品。
我想要实现的是,当我下载一个新的xml PHP代码时,应该检查哪些产品更改了价格和库存价值。
我有一个数组递归方法,它显示了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产品信息。
提前谢谢大家。
答案 0 :(得分:3)
以下代码
它通过迭代旧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元素与新文档进行比较,将新文档与旧文档进行比较。
答案 1 :(得分:0)
尝试这种差异算法:
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