使用php迭代XML文件

时间:2015-03-08 17:00:19

标签: php xml

我有一个包含以下内容的XML文件:

<property>
  <id>1</id>
  <type>type</type>
  <town>town</town>
  <province>province</province>
  <images>
    <image id="1">
    <url>
      http://www.test.com
    </url>
    <image id="2">
    <url>
      http://www.test.com
    </url>
    <image id="3">
    <url>
      http://www.test.com
    </url>
  </image>

我可以遍历文件并获取除图像网址之外的值。 我正在为具有属性的元素之后的元素进行挣扎。

$count=0;
$id=0;
foreach($xml->children() as $properties) {
    echo "<h1>" . $xml->property[$count]->type . " for sale in " .$xml->property[$count]->town . ", " . $xml->property[$count]->province . "</h1>" . "<br>";
    echo $xml->property[$count]->id . "<br>";
    echo $xml->property[$count]->desc->en . "<br>";

    foreach($xml->property[$count]->children() as $images) {
        echo $xml->property[$count]->images -> image[$id++] -> url;
        $id++;
}
    $count++;
}

但是第二个循环并不接近正确。 我非常感谢一些帮助。

2 个答案:

答案 0 :(得分:0)

或许这样的事情:

foreach($xml->property[$count]->images as $image) {
    echo $image->url;
}

答案 1 :(得分:0)

您尚未共享完整的XML结构,因此不清楚文档的根目录(文档元素)。

假设根元素不是<property>但是所有<property>元素都是根元素的子元素,您只需迭代它们就可以迭代所有<property>元素:

$xml = simplexml_load_file('example.xml');

foreach ($xml->property as $property) {
    printf(
        "<h1>%s for sale in %s, %s</h1>\n", htmlspecialchars($property->id), 
        htmlspecialchars($property->town), htmlspecialchars($property->province)
    );

如您所见,您不需要明确地使用$count变量。你可以,但你不需要。只是说。

现在您正在寻找图片网址。每个<property>元素都有一个名为<images>的子元素,这些元素同样具有您感兴趣的多个<url>元素。

这可以通过xpath查询来完成(当您深入到多个级别时):

$urls = $property->xpath('images/image/url');
foreach ($urls as $url) {
    printf(" - %s\n", htmlspecialchars(trim($url)));
}

如果您不在此处使用xpath,则需要为包含多个子级的每个级别创建一个foreach。就像一个反例:

foreach ($property->images->image as $image) {
    foreach ($image->url as $url) {
        printf(" - %s\n", htmlspecialchars(trim($url)));
    }
}

我希望这能更好地告诉你如何在simplexml中进行遍历。 PHP手册中有一些更好的材料,标题为Basic SimpleXML usage,它显示了基本的遍历,还链接到更高级的xpath主题。

当您将动态数据输出到HTML以对其进行正确的HTML编码时,请不要忘记。我已经使用了htmlspecialchars函数,您需要提供正确的编码参数,我在答案中为了简洁而遗漏了这些参数。

完整示例:

<?php
/**
 * @link https://stackoverflow.com/questions/28929239/iterating-through-xml-file-with-php
 */

$buffer = <<<XML
<root>
    <property>
        <id>1</id>
        <type>type</type>
        <town>town</town>
        <province>province</province>
        <images>
            <image id="1">
                <url>
                    http://www.test.com
                </url>
            </image>
            <image id="2">
                <url>
                    http://www.test.com
                </url>
            </image>
            <image id="3">
                <url>
                    http://www.test.com
                </url>
            </image>
        </images>
    </property>
    <property>
        <id>1</id>
        <images>
            <image id="1">
                <url>
                    http://www.test.com
                </url>
            </image>
         </images>
    </property>
</root>
XML;


$xml = simplexml_load_string($buffer);

foreach ($xml->property as $property) {
    printf(
        "<h1>%s for sale in %s, %s</h1>\n",
        htmlspecialchars($property->id), htmlspecialchars($property->town), htmlspecialchars($property->province)
    );

    $urls = $property->xpath('images/image/url');
    foreach ($urls as $url) {
        printf(" - %s\n", htmlspecialchars(trim($url)));
    }
}

示例性输出(纯文本):

<h1>1 for sale in town, province</h1>
 - http://www.test.com
 - http://www.test.com
 - http://www.test.com
<h1>1 for sale in , </h1>
 - http://www.test.com

使用SimpleXML进行音译和输出编码

通过扩展 SimpleXMLElement 的每个字符串值,可以实现全局应用音译(删除重音)和HTML编码(htmlspecialchars)的一种方法。有一个简短的说法: SimpleXMLElement 不能拥有私有属性(因为这些属性都很神奇),但是您可以创建静态全局变量。为了保持Transliterator的实例,这就足够了。对于操纵字符串值,__toString() magic method适用于 SimpleXMLElement

/**
 * Transliterate and HTML encode
 *
 * Class XMLTransliterated
 */
class XMLTransliterated extends SimpleXMLElement
{
    public static $transliterator;

    public function __toString()
    {
        $transliterator = &self::$transliterator;
        $transliterator || $transliterator = Transliterator::create("Latin-ASCII");

        $transliterated = $transliterator->transliterate($this);

        return htmlspecialchars(trim($transliterated), ENT_QUOTES | ENT_HTML5, 'UTF-8');
    }
}

在创建 SimpleXMLElement 时,您需要做的就是使用字符串操作来使用此类名XMLTransliterated(或任何您命名的类):

$xml = simplexml_load_string($buffer, 'XMLTransliterated');

- 或 - 这对于simplexml来说非常特殊,你可以稍后用一点转换技巧改变这个类:

$xml = simplexml_import_dom(dom_import_simplexml($xml), 'XMLTransliterated');

这将使以下代码使用 XMLTransliterated 而不是之前不太具体的 SimpleXMLElement ,因此代码基本保持不变(请注意htmlspecialchars并且trim调用可以安全删除,因为它们在访问 SimpleXMLElement 的字符串值时会自动调用:

$xml = simplexml_load_string($buffer, 'XMLTransliterated');

foreach ($xml->property as $property) {
    printf(
        "<h1>%s (%s) for sale in %s, %s</h1>\n",
        $property->id, $property->type, $property->town, $property->province
    );

    $urls = $property->xpath('images/image/url');
    foreach ($urls as $url) {
        printf(" - %s\n", $url);
    }
}

但输出会变成&#34; Schloß&#34;进入&#34; schloss&#34;,&#34; tôwn&#34;进入&#34; town&#34;和&#34; provincé&#34;进入&#34; province&#34;。

Transliterator 需要PHP 5.4并且启用了Intl extension(如果没有启用它,您应该拥有它)。

或者您也可以使用transliteration from the iconv library。但请注意,这会产生略微不同的输出:

$transliterated = iconv('UTF-8', 'ASCII//IGNORE//TRANSLIT', $this);

更多相关音译问题: