如何将 XML 文件 B 中的现有元素添加到 XML 文件 A

How to add existing elements from XML file B to XML file A

我有 2 个 XML 文件。

我正在尝试从 XML 文件 B 中获取数据并将其添加到 XML 文件 A。我想先添加一个空的 child 到 XML 文件A,然后在 child 中,我想添加来自 XML 文件 B 的数据(在本例中为 animal child 元素)。我想通过 SimpleXML 或 DOMDocument 来实现。我一直坚持这一点。任何帮助都会很棒!

personinfo.xml < XML 文件 A

<personinfo>
    <personN number="1">
        <personL letter="A">
            <fullname>
                <firstname>Summer</firstname>
                <lastname>Smith</lastname>
            </fullname>
            <favourites>
                <color>pink</color>
            </favourites>
        </personL>  
    </personN>

    <personN number="2">
        <personL letter="B">
            <fullname>
                <firstname>Autumn</firstname>
                <lastname>Smith</lastname>
            </fullname>
            <favourites>
                <color>blue</color>
            </favourites>
        </personL>  
    </personN>
</personinfo>

favouritesinfo.xml < XML 文件 B

<favouritesinfo>
    <personN number="1">
            <animal>cat</animal>
    </personN>
    <personN number="2">
            <animal>dog</animal>
    </personN>
</favouritesinfo>

这可能吗?如果是这样,我可以通过 XML DOM Document 或 SimpleXML 来做到这一点吗?

我尝试通过单独的 PHP 文件以这种方式进行操作,但它不会 work/do 任何与 SimpleXML

$personXML = simplexml_load_file("personinfo.xml");
$faveXML = simplexml_load_file("favouritesinfo.xml");

$animal=$faveXML->personN[0]->animal;

$newFave=$personXML->personN->personL[0]->addChild("favourites");
$favourites->addChild($animal);

$personXML->asXML();

期望的输出

<personinfo>
    <personN number="1">
        <personL letter="A">
            <fullname>
                <firstname>Summer</firstname>
                <lastname>Smith</lastname>
            </fullname>
            <favourites>
                <color>pink</color>
            </favourites>
            <favourites>
                <color>cat</color>
            </favourites>
        </personL>  
    </personN>

    <personN number="2">
        <personL letter="B">
            <fullname>
                <firstname>Autumn</firstname>
                <lastname>Smith</lastname>
            </fullname>
            <favourites>
                <color>blue</color>
            </favourites>
            <favourites>
                <color>dog</color>
            </favourites>
        </personL>  
    </personN>
</personinfo>

这在 DOM 中更容易,因为您可以访问节点并可以将它们从一个文档复制到另一个文档。使用 Xpath 获取文档的一部分。

// load the XML into DOM document and create Xpath instances
$personsDocument = new DOMDocument;
$personsDocument->preserveWhiteSpace = FALSE;
$personsDocument->loadXML($xmlPersons);
$personsXpath = new DOMXpath($personsDocument);

$favoritesDocument = new DOMDocument;
$favoritesDocument->preserveWhiteSpace = FALSE;
$favoritesDocument->loadXML($xmlFavorites);
$favoritesXpath = new DOMXpath($favoritesDocument);

// iterate the personN nodes in the favorties XML
foreach ($favoritesXpath->evaluate('.//personN') as $personFavorites) {
    $personId = (int)$personFavorites->getAttribute('number');
    // find the matching personL node in the persons XML
    foreach ($personsXpath->evaluate('.//personN[@number='.$personId.']/personL') as $personNode) {
        // check if it has a 'favourites' child already
        $favoritesNode = $personsXpath->evaluate('favourites', $personNode)->item(0);
        if (!$favoritesNode) {
            // otherwise create one
            $favoritesNode = $personNode->appendChild(
                $personsDocument->createElement('favourites')
            );
        }
        // now iterate the different favorites of a person
        foreach ($personFavorites->childNodes as $favorite) {
            // import and add
            $favoritesNode->appendChild($personsDocument->importNode($favorite, TRUE));
        }
    }
}

$personsDocument->formatOutput = TRUE;
echo $personsDocument->saveXML();

输出:

<?xml version="1.0"?>
<personinfo>
  <personN number="1">
    <personL letter="A">
      <fullname>
        <firstname>Summer</firstname>
        <lastname>Smith</lastname>
      </fullname>
      <favourites>
        <color>pink</color>
        <animal>cat</animal>
      </favourites>
    </personL>
  </personN>
  <personN number="2">
    <personL letter="B">
      <fullname>
        <firstname>Autumn</firstname>
        <lastname>Smith</lastname>
      </fullname>
      <favourites>
        <color>blue</color>
        <animal>dog</animal>
      </favourites>
    </personL>
  </personN>
</personinfo>

为每个收藏添加一个favourites parent 没有多大意义。所以我在我的示例中添加了一个检查。如果你真的想要 parent 个节点,你可以删除它:

foreach ($personsXpath->evaluate('.//personN[@number='.$personId.']/personL') as $personNode) {
    //create 'favourites' child
    $favoritesNode = $personNode->appendChild(
        $personsDocument->createElement('favourites')
    );
    foreach ($personFavorites->childNodes as $favorite) {
    //...

据我所知,纯 SimpleXMLElement 不允许开箱即用地从另一个文档导入节点,但 DOMDocument 可以。

幸运的是,两者可以很好地协同工作,一个简单XML元素可以"turned"变成一个DOM节点和vice-versa。

这就是 dom_import_simplexml() function 的用途。

这是一个与您在问题中的示例相关的示例,但不是使用 SimpleXML::addChild() 导入 DOM 然后将(再次导入) child 添加到DOM元素节点:

$parent = dom_import_simplexml($newFave); # [1]
$parent->appendChild( # [2]
    $parent->ownerDocument->importNode(dom_import_simplexml($animal), true) # [3]
);

echo $personXML->asXML(); # [4]
  1. <favourites> parent 元素创建一个 DOM 节点
  2. 在 DOM parent 节点上附加 child
  3. 创建并导入最喜欢的动物 DOM 节点。该节点需要首先导入到 parent 文档中,因为它是 不同的 DOM 文档的一部分,并且只有在以下情况下才可能添加 child 节点节点是同一文档的一部分。
  4. 使用简单XML元素
  5. 输出

结果(丑陋的打印)如下:

...
        <personL letter="A">
            <fullname>
                <firstname>Summer</firstname>
                <lastname>Smith</lastname>
            </fullname>
            <favourites>
                <color>pink</color>
            </favourites>
        <favourites><animal>cat</animal></favourites></personL>
               ^       ^
               |       |
               |   $animal = $faveXML->personN[0]->animal;
               |   $parent->ownerDocument
               |       ->importNode(dom_import_simplexml($animal), true)
               |
               |

   $newFave = $personXML->personN->personL[0]->addChild("favourites");
...

我希望这很容易理解。这是@ThW 在他的回答中提出的一些建议,但仅在 SimpleXMLElement 无法完成工作的部分使用 DOMDocument。

我也喜欢他的建议,不要一次又一次地添加收藏夹元素。因此,为了获得一种更动态的方法来通过这两个 XML 文档中的人员编号添加人员的收藏夹,让我们添加一些 Xpath 到组合中:

foreach ($faveXML->xpath('./personN[*]') as $person) {
    foreach ($personXML->xpath(
        sprintf('./personN[@number = "%d"]/*/favourites[1]', $person['number'])
    ) as $favourites) {
        $parent = dom_import_simplexml($favourites);
        $parent->appendChild(
            $parent->ownerDocument->importNode(dom_import_simplexml($person->children()[0]), true)
        );
    }
};