首页 > 解决方案 > 如何为某个字段具有某个值的所有产品提取 xml 数据?

问题描述

XML 文件包含 1000 个产品条目。其中一些为国家葡萄牙。我只想获取国家为葡萄牙的产品,并将该信息写入我的服务器上的新 XML 文件。我将如何在 PHP 中做到这一点?

XML 内容结构:

<products>
<product ID="38450">
    <name>Aparthotel Alfagar</name>
    <price currency="EUR">239.00</price>
    <URL>https://website.com/</URL>
    <images>
        <image>https://website.com/1.jpg</image>
        <image>https://website.com/2.jpg</image>
        <image>https://website.com/3.jpg</image>
    </images>
    <description>
        <![CDATA[<p>some text</p>]]>
    </description>
    <categories/>
    <properties>
        <property name="country">
            <value>Portugal</value>
        </property>
        <property name="lowestPrice">
            <value>239.00</value>
        </property>
        <property name="lowestPriceDate">
            <value>13-01-2020</value>
        </property>
    </properties>
    <variations/>
</product>
<!-- more product entries -->

我的方法是这样开始的:

    <?php
// Define source
$source_url = 'https://website.net/?encoding=utf-8&type=xml&id=';

// Define target
$file_url = '/home/website/public_html/media/';
$file_ext = '.xml';

// Load data
$array = simplexml_load_file($source_url.'654321');

// Filter data
$results_portugal = '';
foreach($array->product->properties->property->value['Portugal'] as $results) {

}

// Create datafiles
copy ($results_portugal,$file_url.'portugal'.$file_ext);

显然我很快就被卡住了。谁能帮帮我?提前谢谢了!

标签: phpxmlforeach

解决方案


您可以使用 XPath 表达式在 SimpleXML 或 DOM 中获取 XML 的一部分:

$products = new SimpleXMLElement($xml);

var_dump(
  count(
    $products->xpath('//product[properties/property[@name = "country"]/value = "Portugal"]')
  )
);
var_dump(
  count(
    $products->xpath('//product[properties/property[@name = "country"]/value = "Spain"]')
  )
);

然而,这里不是在 SimpleXML 中复制节点的“好”方式。DOM 允许:

// create source document and load XML
$source = new DOMDocument();
$source->loadXML($xml);
$xpath = new DOMXpath($source);

// create target document and append root node
$target = new DOMDocument();
$target->appendChild($target->createElement('products'));

$expression = '//product[properties/property[@name = "country"]/value = "Portugal"]';

// iterate filtered nodes
foreach ($xpath->evaluate($expression) as $product) {
    // import node into target document and append
    $target->documentElement->appendChild(
        $target->importNode($product, TRUE)
    );
}

echo $target->saveXML();

对于非常大的 XML,您需要使用 XMLReader/XMLWriter。它们允许您仅将 XML 文件的一部分加载到内存中。最初这里不是复制节点的简单方法,但我将其添加到FluentDOM

// Create the target writer and add the root element
$writer = new \FluentDOM\XMLWriter();
$writer->openUri('php://stdout');
$writer->setIndent(2);
$writer->startDocument();
$writer->startElement('products');

// load the source into a reader
$reader = new \FluentDOM\XMLReader();
$reader->open('data://text/plain;base64,'.base64_encode($xml));

// iterate the product elements - the iterator expands them into a DOM node
foreach (new FluentDOM\XMLReader\SiblingIterator($reader, 'product') as $product) {
  /** @var \FluentDOM\DOM\Element $product */
  // validate country property
  if ($product('properties/property[@name = "country"]/value = "Portugal"')) {
    // write expanded node to the output
    $writer->collapse($product);
  }
}

$writer->endElement();
$writer->endDocument(); 

推荐阅读