Как добавить существующие элементы из XML-файла B в XML-файл A - PullRequest
0 голосов
/ 10 октября 2019

У меня есть 2 XML-файла.

Я пытаюсь получить данные из XML-файла B и добавить их в XML-файл A. Я хочу сначала добавить пустой дочерний элемент в XML-файл A, а затем в этом дочернем элементе я хочу добавить данные из XMLФайл B (в данном случае дочерний элемент animal). Я хочу добиться этого с помощью SimpleXML или DOMDocument. Я застрял на этом. Любая помощь будет отличной!

personinfo.xml

<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

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

Возможно ли это? Если да, могу ли я сделать это с помощью XML DOM Document или SimpleXML?

Я пытался сделать это таким образом с помощью отдельного файла PHP, но это не работает / ничего не делает с 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>

Ответы [ 2 ]

0 голосов
/ 12 октября 2019

Из того, что я знаю, чистый SimpleXMLElement не позволяет импортировать узлы из другого документа из коробки, но DOMDocument делает это.

К счастью, оба хорошо работают вместе, SimpleXMLElement можно «превратить» в DOMNode и наоборот. -versa.

Это то, для чего предназначена функция dom_import_simplexml() .

Вот пример, который относится к примеру, который у вас есть в вашем вопросе, но вместо использованияSimpleXML::addChild() импорт в DOM и добавление (снова импортированного) дочернего элемента в узел DOMElement:

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

echo $personXML->asXML(); # [4]
  1. создание узла DOM для родительского элемента <favourites>
  2. appendдочерний узел родительского узла DOM
  3. создает и импортирует любимый узел DOM животного. Узел необходимо сначала импортировать в родительский документ, поскольку он является частью другого DOMDocument, и добавление дочерних узлов возможно только в том случае, если узлы являются частью одного и того же документа.
  4. вывод сthe SimpleXMLElement

Результат (напечатанный безобразно) выглядит так:

...
        <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 предлагает в своем ответе, но использует DOMDocument только для той части, где SimpleXMLElement не может выполнить эту работу.

Также мне нравится его предложение не добавлять элемент избранного снова и снова. Так что для более динамичного подхода к добавлению избранных лиц по количеству людей в этих двух 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)
        );
    }
};
0 голосов
/ 10 октября 2019

Это проще в 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 родителя для каждого избранного не имеет особого смысла. Поэтому я добавил чек в мой пример. Если вы действительно хотите родительские узлы, вы можете удалить его:

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