Соедините два XML-файла с соответствующим узлом в php

#php #xml

Вопрос:

Мне нужно подключить 2 hml с помощью ключа. Я использовал код, найденный здесь. Но я не могу им воспользоваться. Я попытался найти здесь аналогичные вопросы и решения. Но они были с одним и тем же именем поля «Код продукта». Моя задача сложнее. Идентификаторы разные, но значения одни и те же. «Код продукта» и «WIC»

xml1

 <ProductCode>VCQP620V2-PB</ProductCode>
<Vendor>PNY</Vendor>
<ProductType>Графические процессоры</ProductType>
<ProductCategory>Видеокарты</ProductCategory>
<ProductDescription>PNY NVIDIA QUADRO P620</ProductDescription>
<ProductCard>https://content.it4profit.com/itshop/itemcard_cs.jsp?ITEM=200331123012134965amp;amp;THEME=asbisamp;amp;LANG=ru</ProductCard>
<AttrList>
  <element Name="Стандарт разъема подключения" Value="PCI Express 3.0 x16"/>
</AttrList>
<Images>
  <Image>https://content.it4profit.com/pimg/s/resize/600x600x600x600/200401160012256800.jpg</Image>
</Images>
 

xml2

 <CONTENT>
<COMP_CODE>720</COMP_CODE>
<LANG>ru</LANG>
<COMP_CODE_BUYER>210629085533538169</COMP_CODE_BUYER>
<SEARCH_CODE></SEARCH_CODE>
<MANUFACTURER_NAME></MANUFACTURER_NAME>
<TYPE_NAME></TYPE_NAME>
<SUPPLY_TYPE></SUPPLY_TYPE>
<PRICES>
    <PRICE>
        <WIC>VCQP620V2-PB</WIC>
        <DESCRIPTION>PNY NVIDIA QUADRO P620 2GB GDDR5, 128-bit, PCIEx16 2.0, mini DP 1.4 x4, Active cooling, TDP 40W, LP, Retail (4 х mDP на DP, 1 × mDP to DVI-D SL, 1 x LP Bracket included)</DESCRIPTION>
        <VENDOR_NAME>PNY</VENDOR_NAME>
        <GROUP_NAME>Graphics Processing Unit</GROUP_NAME>
        <VPF_NAME/>
        <CURRENCY_CODE>KZT</CURRENCY_CODE>
        <AVAIL>0</AVAIL>
        <RETAIL_PRICE>103857.95</RETAIL_PRICE>
        <MY_PRICE>103857.95</MY_PRICE>
        <WARRANTYTERM>24</WARRANTYTERM>
        <GROUP_ID>852</GROUP_ID>
        <VENDOR_ID>170544</VENDOR_ID>
        <SMALL_IMAGE>https://www.it4profit.com/catalogimg/wic/1/VCQP620V2-PB</SMALL_IMAGE>
        <PRODUCT_CARD>https://content.it4profit.com/itshop/itemcard_cs.jsp?ITEM=200331123012134965amp;amp;THEME=asbisamp;amp;LANG=ru</PRODUCT_CARD>
        <EAN/>
    </PRICE>
</PRICES>
 

Объедините XML. Я бы хотел, чтобы все было так.

 <ProductCode>VCQP620V2-PB</ProductCode>

<Vendor>PNY</Vendor>

<ProductType>Графические процессоры</ProductType>

<ProductCategory>Видеокарты</ProductCategory>

<ProductDescription>PNY NVIDIA QUADRO P620</ProductDescription>
<Image>https://www.it4profit.com/catalogimg/wic/1/VCQP620V2-PB</Image>
<ProductCard>https://content.it4profit.com/itshop/itemcard_cs.jsp?ITEM=200331123012134965amp;amp;THEME=asbisamp;amp;LANG=ru</ProductCard>

<RETAIL_PRICE>103857.95</RETAIL_PRICE>
<MY_PRICE>103857.95</MY_PRICE>
<AVAIL>0</AVAIL>


<AttrList>
  <element Name="Стандарт разъема подключения" Value="PCI Express 3.0 x16"/>
</AttrList>
<Images>
  <Image>https://content.it4profit.com/pimg/s/resize/600x600x600x600/200401160012256800.jpg</Image>
</Images>
 

Ответ №1:

DOM Xpath позволяет настраивать таргетинг и копировать узлы:

Вы пропустили некоторые родительские элементы. Я добавил некоторые, чтобы получить действительный XML, и удалил некоторые незатронутые/неиспользуемые листовые элементы.

Вот объясненный пример:

 // bootstrap the XML documents
$mainDocument = new DOMDocument();
$mainDocument->preserveWhiteSpace = FALSE;
$mainDocument->loadXML(getMainXML());
$mainXpath = new DOMXpath($mainDocument);

$dataDocument = new DOMDocument();
$mainDocument->preserveWhiteSpace = FALSE;
$dataDocument->loadXML(getDataXML());
$dataXpath = new DOMXpath($dataDocument);

// iterate the Product elements
foreach ($mainXpath->evaluate('//Product') as $product) {
    // get the Product Code
    $productCode = $mainXpath->evaluate('string(ProductCode)', $product);
    
    // Look for the first PRICE with a matching WIC
    foreach ($dataXpath->evaluate("(//PRICE[WIC='$productCode'])[1]") as $price) {
        
        // any child element (*), filtered by element name
        $nodesToCopy = $dataXpath->evaluate(
            '*[self::RETAIL_PRICE or self::MY_PRICE or self::AVAIL]',
            $price
        );
        foreach ($nodesToCopy as $node) {
            // import and append
            $product->appendChild($mainDocument->importNode($node, TRUE));
        }  
    }
}


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


function getMainXML() {
    return <<<'XML'
<?xml version="1.0" encoding="utf-8"?>
<Products>
    <Product>
        <ProductCode>VCQP620V2-PB</ProductCode>
        <Vendor>PNY</Vendor>
        <ProductType>Графические процессоры</ProductType>
        <ProductCategory>Видеокарты</ProductCategory>
    </Product>
</Products>
XML;
}

function getDataXML() {
    return <<<'XML'
<CONTENT>
    <PRICES>
        <PRICE>
            <WIC>VCQP620V2-PB</WIC>
            <CURRENCY_CODE>KZT</CURRENCY_CODE>
            <AVAIL>0</AVAIL>
            <RETAIL_PRICE>103857.95</RETAIL_PRICE>
            <MY_PRICE>103857.95</MY_PRICE>
            <WARRANTYTERM>24</WARRANTYTERM>
            <GROUP_ID>852</GROUP_ID>
            <VENDOR_ID>170544</VENDOR_ID>
            <EAN/>
        </PRICE>
    </PRICES>
</CONTENT>
XML;
}
 

Выход:

 <?xml version="1.0" encoding="utf-8"?>
<Products>
  <Product>
    <ProductCode>VCQP620V2-PB</ProductCode>
    <Vendor>PNY</Vendor>
    <ProductType>Графические процессоры</ProductType>
    <ProductCategory>Видеокарты</ProductCategory>
    <AVAIL>0</AVAIL>
    <RETAIL_PRICE>103857.95</RETAIL_PRICE>
    <MY_PRICE>103857.95</MY_PRICE>
  </Product>
</Products>
 

Однако, если ваши документы очень велики, вам может потребоваться заглянуть в XmlReader и выполнить временный импорт базы данных.