【问题标题】:Merge two xml files based on common attribute根据共同属性合并两个xml文件
【发布时间】:2014-03-31 16:08:43
【问题描述】:

我有两个结构相似的xml文件,我需要基于一个共同的属性来合并它们。更明确地说,这里有两个示例:

file1.xml

 <Products>
 <record ProductId="366" ProductName="Test" ProductCategory="Categ1"></record>
 </Products>

file2.xml

 <Productprices>
 <record ProductId="366" ProductPrice="10" ProductVAT="24"></record>
 </Productprices>

这两个文件的共同属性是 ProductId。我需要合并所有属性,以便合并后的文件如下所示:

 <Products>
 <record ProductId="366" ProductName="Test" ProductCategory="Categ1" ProductPrice="10" ProductVAT="24"></record>
 </Products>

不幸的是,到目前为止我所做的只是合并两个文件,合并后的文件如下所示:

 <Products>
 <record ProductId="366" ProductName="Test" ProductCategory="Categ1"></record>
 <record ProductId="366" ProductPrice="10" ProductVAT="24"></record>
 </Products>

这是我使用的 PHP 代码:

 $doc1 = new DOMDocument();
 $doc1->load('file1.xml');
 $doc2 = new DOMDocument();
 $doc2->load('file2.xml');
 $res1 = $doc1->getElementsByTagName('Products')->item(0);
 $items2 = $doc2->getElementsByTagName('record');
 for ($i = 0; $i < $items2->length; $i ++) {
 $item2 = $items2->item($i);
 $item1 = $doc1->importNode($item2, true);
 $res1->appendChild($item1);
 }
 $doc1->save('file1.xml');

有没有什么方法可以使用 DomDocument 将所有属性合并到一个基于通用 ProductId 的记录中?我宁愿不进入 XSLT。

任何帮助将不胜感激。

提前致谢。

【问题讨论】:

    标签: php xml xml-parsing merge


    【解决方案1】:

    我使用 Xpath 从 DOM 中获取节点和值。在你的情况下,我看到了两个任务。

    一个任务是迭代文档中的所有记录元素,从第二个文档中获取匹配元素的属性并复制属性。

    如果这里没有具有该 ProductId 的元素,则另一个任务是迭代第二个文档中的所有记录元素并将它们添加到第一个文档中。

    $xmlOne = <<<'XML'
    <Products>
     <record ProductId="366" ProductName="Test" ProductCategory="Categ1"></record>
    </Products>
    XML;
    
    $xmlTwo = <<<'XML'
    <Productprices>
     <record ProductId="366" ProductPrice="10" ProductVAT="24"></record>
     <record ProductId="444" ProductPrice="23" ProductVAT="32"></record>
    </Productprices>
    XML;
    
    $targetDom = new DOMDocument();
    $targetDom->loadXml($xmlOne);
    $targetXpath = new DOMXpath($targetDom);
    
    $addDom = new DOMDocument();
    $addDom->loadXml($xmlTwo);
    $addXpath = new DOMXpath($addDom);
    
    // merge attributes of record elements depending on ProductId
    foreach ($targetXpath->evaluate('//record[@ProductId]') as $record) {
      $productId = $record->getAttribute('ProductId');
      foreach ($addXpath->evaluate('//record[@ProductId='.$productId.']/@*') as $attribute) {
        if (!$record->hasAttribute($attribute->name)) {
          $record->setAttribute($attribute->name, $attribute->value);
        }
      }
    }
    
    // copy records elements that are not in target dom
    foreach ($addXpath->evaluate('//record[@ProductId]') as $record) {
      $productId = $record->getAttribute('ProductId');
      if ($targetXpath->evaluate('count(//record[@ProductId='.$productId.'])') == 0) {
        $targetDom->documentElement->appendChild(
          $targetDom->importNode($record)
        );
      }
    }
    
    echo $targetDom->saveXml();
    

    【讨论】:

    • 看起来不错,但是我遇到了一个小问题(我对此很陌生)。我正在尝试像这样加载两个 xml 文件: $xmlOne = '/var/www/html/test/file1.xml' 和 $xmlTwo = '/var/www/html/test/file2.xml' 但我得到了php 中的以下错误: DOMDocument::loadXML() 期望参数 1 是字符串,对象在 ... .你能指出我正确的方向吗?非常感谢。
    • DOMDocument::loadXml() 用于 xml 字符串,DOMDocument::load() 用于 xml 文件。
    【解决方案2】:

    可以使用SimpleXML的attribute()函数

    $xml = simplexml_load_file($filename);
    foreach($xml->Products->record->attributes() as $attribute => $value) {
        //do something
    }
    

    【讨论】:

      猜你喜欢
      • 2023-04-03
      • 1970-01-01
      • 2019-03-01
      • 2016-01-12
      • 1970-01-01
      • 1970-01-01
      • 2018-12-05
      • 2016-10-24
      • 1970-01-01
      相关资源
      最近更新 更多