求助:使用PHP SimpleXML比较、合并XML文件并保存的实现
PHP SimpleXML: Merge Two XML Files (Add Missing Items)
Hey there! Let's get your XML merge script working properly. Your approach is on the right track, but we need to fix how we compare and add the missing items—since array_diff doesn't work directly with SimpleXMLElement objects. Here's a revised solution, plus breakdowns of what was adjusted:
Your Source Files
catalog.xml (Source with extra items)
<?xml version="1.0" encoding="ISO-8859-1"?> <catalog> <item> <name>King of Hearts</name> <category>playing cards</category> <class>Hearts</class> <filter>King</filter> </item> <item> <name>Ace of Spades</name> <category>playing cards</category> <class>Spades</class> <filter>Ace</filter> </item> <item> <name>Eight of Diamonds</name> <category>playing cards</category> <class>Diamonds</class> <filter>Eight</filter> </item> </catalog>
user.xml (Target to update)
<?xml version="1.0" encoding="ISO-8859-1"?> <catalog> <item> <name>Ace of Spades</name> <category>playing cards</category> <class>Spades</class> <filter>Ace</filter> </item> <item> <name>Knight of Clubs</name> <category>playing cards</category> <class>Clubs</class> <filter>Knight</filter> </item> </catalog>
Fixed PHP Script: merge.php
<?php // Load source and target XML files $sourceXml = simplexml_load_file('catalog.xml'); $targetXml = simplexml_load_file('user.xml'); // Step 1: Create an array of existing item names in target XML for quick lookup $existingItems = []; foreach ($targetXml->item as $item) { $existingItems[(string)$item->name] = true; } // Step 2: Add missing items from source to target foreach ($sourceXml->item as $sourceItem) { $itemName = (string)$sourceItem->name; // Check if this item is NOT already in the target if (!isset($existingItems[$itemName])) { // Create a new <item> node in the target $newItem = $targetXml->addChild('item'); // Copy all child elements from source item to the new item $newItem->addChild('name', (string)$sourceItem->name); $newItem->addChild('category', (string)$sourceItem->category); $newItem->addChild('class', (string)$sourceItem->class); $newItem->addChild('filter', (string)$sourceItem->filter); } } // Step 3: Save the updated XML to a new file $targetXml->asXML('user-updated.xml'); echo "Merge completed! Check user-updated.xml"; ?>
What Changed & Why
- Quick Lookup Array: We first extract all existing
<name>values fromuser.xmlinto an array. This lets us check if an item exists in O(1) time, which is much more efficient than comparing entire nodes directly. - Proper Node Addition: Instead of using
array_diff(which doesn't work with SimpleXMLElement objects), we loop through each item in the source XML. For each item, we check if its name is missing from the target—if so, we create a new<item>node and copy all its child elements. - String Casting: We cast SimpleXMLElement values to strings (e.g.,
(string)$sourceItem->name) to avoid issues with object comparisons.
Result: user-updated.xml
After running the script, you'll get the merged XML exactly as you wanted:
<?xml version="1.0" encoding="ISO-8859-1"?> <catalog> <item> <name>Ace of Spades</name> <category>playing cards</category> <class>Spades</class> <filter>Ace</filter> </item> <item> <name>Knight of Clubs</name> <category>playing cards</category> <class>Clubs</class> <filter>Knight</filter> </item> <item> <name>King of Hearts</name> <category>playing cards</category> <class>Hearts</class> <filter>King</filter> </item> <item> <name>Eight of Diamonds</name> <category>playing cards</category> <class>Diamonds</class> <filter>Eight</filter> </item> </catalog>
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

