在 PHP 中合并 XML 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10163675/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Merge XML files in PHP
提问by andrewpo
I have 2 files 1.xmland 2.xmlboth having similar structure and I would like to have one. I tried many solutions but I had errors only - frankly speaking I have no idea how those scripts worked.
我有 2 个文件,1.xml并且2.xml都具有相似的结构,我想要一个。我尝试了很多解决方案,但只有错误 - 坦率地说,我不知道这些脚本是如何工作的。
1.xml:
1.xml:
<res>
<items total="180">
<item>
<id>1</id>
<title>Title 1</title>
<author>Author 1</author>
</item>
...
</items>
</res>
2.xml:
2.xml:
<res>
<items total="123">
<item>
<id>190</id>
<title>Title 190</title>
<author>Author 190</author>
</item>
...
</items>
</res>
I would like to create a new file merged.xmlwith the following structure
我想创建一个merged.xml具有以下结构的新文件
<res>
<items total="303">
<item>
<id>1</id>
<title>Title 1</title>
<author>Author 1</author>
</item>
... //items from 1.xml
<item>
<id>190</id>
<title>Title 190</title>
<author>Author 190</author>
</item>
... //items from 2.xml
</items>
</res>
How should I do that? Can you explain me the way to do it? How can I do it with more files? Thanks
我该怎么做?你能解释一下怎么做吗?我该如何处理更多文件?谢谢
Edit
编辑
What I tried?
我尝试了什么?
<?php
function mergeXML(&$base, $add)
{
if ( $add->count() != 0 )
$new = $base->addChild($add->getName());
else
$new = $base->addChild($add->getName(), $add);
foreach ($add->attributes() as $a => $b)
{
$new->addAttribute($a, $b);
}
if ( $add->count() != 0 )
{
foreach ($add->children() as $child)
{
mergeXML($new, $child);
}
}
}
$xml = mergeXML(simplexml_load_file('1.xml'), simplexml_load_file('2.xml'));
echo $xml->asXML(merged.xml);
?>
EDIT2
编辑2
Following Torious advice I looked into DOMDocument manual and found an example:
按照 Torious 的建议,我查看了 DOMDocument 手册并找到了一个示例:
function joinXML($parent, $child, $tag = null)
{
$DOMChild = new DOMDocument;
$DOMChild->load($child);
$node = $DOMChild->documentElement;
$DOMParent = new DOMDocument;
$DOMParent->formatOutput = true;
$DOMParent->load($parent);
$node = $DOMParent->importNode($node, true);
if ($tag !== null) {
$tag = $DOMParent->getElementsByTagName($tag)->item(0);
$tag->appendChild($node);
} else {
$DOMParent->documentElement->appendChild($node);
}
return $DOMParent->save('merged.xml');
}
joinXML('1.xml', '2.xml')
But it creates wrong xml file:
但它创建了错误的 xml 文件:
<res>
<items total="180">
<item>
<id>1</id>
<title>Title 1</title>
<author>Author 1</author>
</item>
...
</items>
<res>
<items total="123">
<item>
<id>190</id>
<title>Title 190</title>
<author>Author 190</author>
</item>
...
</items>
</res>
</res>
And I cannot use this file properly. I need correct structure and here I have kind of pasting one file into another. I would like to "paste" only item's not all tags. What should I change?
而且我无法正确使用此文件。我需要正确的结构,在这里我可以将一个文件粘贴到另一个文件中。我想“粘贴”仅项目而不是所有标签。我应该改变什么?
EDIT3
编辑3
here is an answer - based on Torious answer - just adapted it to my needs - check //edited
这是一个答案 - 基于 Torious 的答案 - 只是根据我的需要进行了调整 - 检查 //edited
$doc1 = new DOMDocument();
$doc1->load('1.xml');
$doc2 = new DOMDocument();
$doc2->load('2.xml');
// get 'res' element of document 1
$res1 = $doc1->getElementsByTagName('items')->item(0); //edited res - items
// iterate over 'item' elements of document 2
$items2 = $doc2->getElementsByTagName('item');
for ($i = 0; $i < $items2->length; $i ++) {
$item2 = $items2->item($i);
// import/copy item from document 2 to document 1
$item1 = $doc1->importNode($item2, true);
// append imported item to document 1 'res' element
$res1->appendChild($item1);
}
$doc1->save('merged.xml'); //edited -added saving into xml file
采纳答案by Torious
Since you've put an effort in, I've coded something that should work.
既然你已经付出了努力,我已经编写了一些应该可以工作的东西。
Note that this is untested code, but you get the idea.
请注意,这是未经测试的代码,但您明白了。
It's up to you to make it into pretty functions. Make sure you understand what's going on; being able to work with the DOM will probably help you out in a lot of future scenarios. The cool thing about the DOM standard is that you have pretty much the same operations in many different programming languages/platforms.
由你来制作漂亮的功能。确保您了解正在发生的事情;能够使用 DOM 可能会在很多未来的场景中帮助你。DOM 标准很酷的一点是,您可以在许多不同的编程语言/平台中进行几乎相同的操作。
$doc1 = new DOMDocument();
$doc1->load('1.xml');
$doc2 = new DOMDocument();
$doc2->load('2.xml');
// get 'res' element of document 1
$res1 = $doc1->getElementsByTagName('res')->item(0);
// iterate over 'item' elements of document 2
$items2 = $doc2->getElementsByTagName('item');
for ($i = 0; $i < $items2->length; $i ++) {
$item2 = $items2->item($i);
// import/copy item from document 2 to document 1
$item1 = $doc1->importNode($item2, true);
// append imported item to document 1 'res' element
$res1->appendChild($item1);
}
回答by u7565209
I think the most simplest way is changing XML to array first, combine two array which are much more easier and straightforward. Finally change array back to xml. It may helps for the situation when you want to combine two XML files directly. You only need to consider which key is the position you wanna add the child nodes.
我认为最简单的方法是先将 XML 更改为数组,然后将两个数组组合起来更容易和直接。最后将数组改回xml。当您想直接组合两个 XML 文件时,它可能会有所帮助。您只需要考虑哪个键是您要添加子节点的位置。
function xml_to_array($sxi){
$a = array();
for( $sxi->rewind(); $sxi->valid(); $sxi->next() ) {
if(!array_key_exists($sxi->key(), $a)){
$a[$sxi->key()] = array();
}
if($sxi->hasChildren()){
$a[$sxi->key()] = $this->xml_to_array($sxi->current());
}
else{
$a[$sxi->key()] = strval($sxi->current());
}
}
return $a;
}
function array_to_xml( $data, &$xml_data ) {
foreach( $data as $key => $value ) {
if( is_numeric($key) ){
$key = 'item'.$key; //dealing with <0/>..<n/> issues
}
if( is_array($value) ) {
$subnode = $xml_data->addChild($key);
array_to_xml($value, $subnode);
} else {
$xml_data->addChild("$key",htmlspecialchars("$value"));
}
}
}
Useage: Create a SimpleXMLIterator
用途:创建一个 SimpleXMLIterator
$xml1 = new \SimpleXMLIterator('test1.xml',null,true);
$a = xml_to_array($xml1); //convert xml to array
$xml2 = new \SimpleXMLIterator('test2.xml',null,true);
$b = xml_to_array($xml2);
$c = new SimpleXMLElement('<?xml version="1.0"?><data></data>');
$a['new_node']=$b;
array_to_xml($a,$c);
var_dump($c);
回答by Jochen Schultz
How about :
怎么样 :
<?php
// Read file 1
$xmlfilecontent = file_get_contents('xml1.xml');
// Concat file 2
$xmlfilecontent .= file_get_contents('xml2.xml');
// remove <items> tags
preg_replace('/<items[^"]*">/','',$xmlfilecontent);
// remove </items> tags
$xmlfilecontent = str_replace('</items>','',$xmlfilecontent );
// remove <res> tags
$xmlfilecontent = str_replace('<res>','',$xmlfilecontent );
// remove </res> tags
$xmlfilecontent = str_replace('</res>','',$xmlfilecontent );
// load XML Object - also add res and items + amount
$xmlobj = simple_xml_load_string('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'.PHP_EOL.'<res>'.PHP_EOL.'<items total="'.substr_count( $xmlfilecontent , '<item>').'">'.PHP_EOL.$xmlfilecontent.PHP_EOL.'</items>'.PHP_EOL.'</res>');

