Определите элемент XML и скопируйте родительский узел во внешний файл XML, используя переполнение стека.

Я анализирую XML-файл (source.xml) в PHP и мне нужно определить случаи, когда <property> узел содержит <rent> элемент.

Однажды определили весь <property> родительский узел для этой записи должен быть скопирован в отдельный файл XML (destination.xml).

По завершении копии, которая <property> узел должен быть удален из файла source.xml.

Вот пример файла source.xml:

<?xml version="1.0" encoding="utf-8"?>
<root>
<property>
...
<rent>
<term>long</term>
<freq>month</freq>
<price_peak>1234</price_peak>
<price_high>1234</price_high>
<price_medium>1234</price_medium>
<price_low>1234</price_low>
</rent>
...
</property>
</root>

Я пытался использовать DOM с приведенным ниже кодом, однако я не получаю никаких результатов, несмотря на то, что они являются сотнями узлов, которые соответствуют вышеуказанным требованиям. Вот что у меня так далеко:

$destination = new DOMDocument;
$destination->preserveWhiteSpace = true;
$destination->load('destination.xml');

$source = new DOMDocument;
$source->load('source.xml');

$xp = new DOMXPath($source);

foreach ($xp->query('/root/property/rent[term/freq/price_peak/price_high/price_medium/price_low]') as $item) {

$newItem = $destination->documentElement->appendChild(

$destination->createElement('property')

);

foreach (array('term', 'freq', 'price_peak', 'price_high', 'price_medium', 'price_low') as $elementName) {

$newItem->appendChild(
$destination->importNode(
$item->getElementsByTagName($elementName)->property(0),
true
)
);
}
}

$destination->formatOutput = true;
echo $destination->saveXml();

Я только начал узнавать о DOMDocument и его использовании, так что я явно где-то напутал, поэтому любая помощь приветствуется. Большое спасибо.

1

Решение

Трудность заключается в том, когда вы пытаетесь скопировать узел из одного документа в другой. Вы можете попытаться воссоздать узел, скопировав все компоненты, но это тяжелая работа (и подвержена ошибкам). Вместо этого вы можете импортировать узел из одного документа в другой, используя importNode, Второй параметр говорит, что копировать также все дочерние элементы.

Затем удаление элемента из исходного документа — это случай, когда элемент «удаляет себя из своего родителя», что звучит странно, но так работает этот код.

<?php
error_reporting ( E_ALL );
ini_set ( 'display_errors', 1 );

$destination = new DOMDocument;
$destination->preserveWhiteSpace = true;
$destination->loadXML('<?xml version="1.0" encoding="utf-8"?><root></root>');

$source = new DOMDocument;
$source->load('NewFile.xml');

$xp = new DOMXPath($source);
$destRoot = $destination->getElementsByTagName("root")->item(0);
foreach ($xp->query('/root/property[rent]') as $item) {
$newItem = $destination->importNode($item, true);
$destRoot->appendChild($newItem);
$item->parentNode->removeChild($item);
}

echo "Source:".$source->saveXML();
$destination->formatOutput = true;
echo "destination:".$destination->saveXml();

Что касается пункта назначения, я начинаю с базового <root> элемент, а затем добавить содержимое оттуда.

2

Другие решения

Вы хотели получить что-то подобное? Надеюсь это поможет:

$inXmlFile = getcwd() . "/source.xml";
$inXmlString = file_get_contents($inXmlFile);
$outXmlFile = getcwd() . "/destination.xml";
$outXmlString = file_get_contents($outXmlFile);

$sourceDOMDocument = new DOMDocument;
$sourceDOMDocument->loadXML($inXmlString);

$sourceRoot = null;
foreach ($sourceDOMDocument->childNodes as $childNode) {
if(strcmp($childNode->nodeName, "root") == 0) {
$sourceRoot = $childNode;
break;
}
}

$destDOMDocument = new DOMDocument;
$destDOMDocument->loadXML($outXmlString);

$destRoot = null;
foreach ($destDOMDocument->childNodes as $childNode) {
if(strcmp($childNode->nodeName, "root") == 0) {
$destRoot = $childNode;
break;
}
}

$xmlStructure = simplexml_load_string($inXmlString);

$domProperty = dom_import_simplexml($xmlStructure->property);

$rents = $domProperty->getElementsByTagName('rent');
if(($rents != null) && (count($rents) > 0)) {
$destRoot->appendChild($destDOMDocument->importNode($domProperty->cloneNode(true), true));
$destDOMDocument->save($outXmlFile);
$sourceRoot->removeChild($sourceRoot->getElementsByTagName('property')->item(0));
$sourceDOMDocument->save($inXmlFile);
}
0

Попробуйте запустить два преобразования XSLT: одно, которое добавляет <property><rent> узлы в пункте назначения и тот, который удаляет эти узлы из источника. В качестве фона, XSLT является языком специального назначения, предназначенным для преобразования файлов XML даже при сохранении document() функция для анализа из внешних файлов XML в той же папке или подпапке.

PHP может запускать сценарии XSLT 1.0 с его PHP-XSL класс (обязательно включите расширение в файле .ini). При таком подходе нет if логика или foreach петли нужны.

XSLT Сценарии

PropertyRentAdd.xsl (убедитесь, что source.xml и XSLT находятся в одной папке)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- IDENTITY TRANSFORM -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<!-- ADD TEMPLATE -->
<xsl:template match="root">
<xsl:copy>
<xsl:copy-of select="*"/>
<xsl:copy-of select="document('source.xml')/root/property[local-name(*)='rent']"/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

PropertyRentRemove.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- IDENTITY TRANSFORM -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<!-- REMOVE TEMPLATE -->
<xsl:template match="property[local-name(*)='rent']">
</xsl:template>

</xsl:stylesheet>

PHP

// Set current path
$cd = dirname(__FILE__);

// Load the XML and XSLT files
$doc = new DOMDocument();
$doc->load($cd.'/destination.xml');

$xsl = new DOMDocument;
$xsl->load($cd.'/PropertRentAdd.xsl');

// Transform the destination xml
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
$newXml = $proc->transformToXML($xml);

// Save output to file, overwriting original
file_put_contents($cd.'/destination.xml', $newXml);// Load the XML and XSLT files
$doc = new DOMDocument();
$doc->load($cd.'/source.xml');

$xsl = new DOMDocument;
$xsl->load($cd.'/PropertRentRemove.xsl');

// Transform the source xml
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
$newXml = $proc->transformToXML($xml);

// Save output overwriting original file
file_put_contents($cd.'/source.xml', $newXml);

входные (примеры для демонстрации, с другими тегами для отображения содержимого не влияет)

source.xml

<?xml version="1.0" encoding="utf-8"?>
<root>
<property>
<rent>
<term>long</term>
<freq>month</freq>
<price_peak>1234</price_peak>
<price_high>1234</price_high>
<price_medium>1234</price_medium>
<price_low>1234</price_low>
</rent>
</property>
<property>
<rent>
<term>short</term>
<freq>month</freq>
<price_peak>7890</price_peak>
<price_high>7890</price_high>
<price_medium>7890</price_medium>
<price_low>7890</price_low>
</rent>
</property>
<property>
<web_site>stackoverflow</web_site>
<general_purpose>php</general_purpose>
</property>
<property>
<web_site>stackoverflow</web_site>
<special_purpose>xsl</special_purpose>
</property>
</root>

destination.xml

<?xml version="1.0" encoding="utf-8"?>
<root>
<original_data>
<test1>ABC</test1>
<test2>123</test2>
</original_data>
<original_data>
<test1>XYZ</test1>
<test2>789</test2>
</original_data>
</root>

Выход (после запуска PHP)

source.xml

<?xml version="1.0"?>
<root>
<property>
<web_site>stackoverflow</web_site>
<general_purpose>php</general_purpose>
</property>
<property>
<web_site>stackoverflow</web_site>
<special_purpose>xsl</special_purpose>
</property>
</root>

destination.xml (новые узлы добавлены внизу)

<?xml version="1.0"?>
<root>
<original_data>
<test1>ABC</test1>
<test2>123</test2>
</original_data>
<original_data>
<test1>XYZ</test1>
<test2>789</test2>
</original_data>
<property>
<rent>
<term>long</term>
<freq>month</freq>
<price_peak>1234</price_peak>
<price_high>1234</price_high>
<price_medium>1234</price_medium>
<price_low>1234</price_low>
</rent>
</property>
<property>
<rent>
<term>short</term>
<freq>month</freq>
<price_peak>7890</price_peak>
<price_high>7890</price_high>
<price_medium>7890</price_medium>
<price_low>7890</price_low>
</rent>
</property>
</root>
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector