Показать различия между 2 XML-файлами (с php) - PullRequest
3 голосов
/ 10 июля 2011

У меня есть 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;
}

canКто-нибудь поможет мне показать не только поле различий в XML, но и всю информацию о продукте XML, которая была изменена.

Заранее всем спасибо.

Ответы [ 2 ]

3 голосов
/ 10 июля 2011

Следующий код будет

  • найти и отобразить externalXML элементов продукта
  • с одинаковым идентификатором продукта
  • но отличаются либо ценой, либо запасом.

Он работает путем итерации всех элементов продукта в старом XML, сбора их product_id, цены и стоимости акций и объединения их в запрос XPath, который затем выполняется для нового документа.

с DOM

$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);
}

С SimpleXml

$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 из старого документа с новым документом, а другой - из нового документа в старый.

0 голосов
/ 10 июля 2011

Попробуйте этот алгоритм сравнения:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...