简体   繁体   English

用php遍历XML文件

[英]Iterating through XML file with php

I have an XML file with the following: 我有一个包含以下内容的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>

I can iterate through the file and get the value except the image url. 我可以遍历文件并获取除图像URL之外的值。 I am struggling with the element after the element with an attribute. 我正在为具有属性的元素在元素之后苦苦挣扎。

$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++;
}

but the 2nd loop isn´t close to being right. 但是第二个循环并不太正确。 I would greatly appreciate some help. 我将不胜感激一些帮助。

Something like this perhaps: 大概是这样的:

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

You have not shared the complete XML structure so it's unclear where the root of the document is (the document element). 您尚未共享完整的XML结构,因此尚不清楚文档根目录(文档元素)在哪里。

Assuming that the root element is not <property> but all <property> elements are children of the root element you can iterate over all those <property> elements by simply just iterating over them: 假设根元素不是<property>但所有<property>元素都是root元素的子元素,则可以通过仅对它们进行迭代来遍历所有这些<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)
    );

As you can see, you don't need to make use of a $count variable explicitly. 如您所见,您不需要显式使用$count变量。 You can, but you don't need to. 可以,但是不需要。 Just saying. 只是说。

Now you're looking for the image URLs. 现在,您正在寻找图像URL。 Each <property> element has a single child element named <images> and these again have mulitple <url> elements you're interested in. 每个<property>元素都有一个名为<images>子元素,而这些子元素又具有您感兴趣的多个<url>元素。

This can be done with an xpath query (as you go down deeper more than one level): 这可以通过xpath查询来完成(当您深入到多个层次时):

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

If you don't use xpath here, you would have needed to make a foreach for every single level that contains more than a single child. 如果您在此处不使用xpath,则需要为每个包含多个子代的单个级别创建一个foreach。 Just as a counter-example: 只是一个反例:

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

I hope this shows you more well how the traversal works in simplexml. 我希望这能更好地向您展示遍历如何在simplexml中工作。 There is some more great material in the PHP manual entitled Basic SimpleXML usage which shows basic traversal and also links to the more advanced xpath topic. PHP手册中有一些更棒的材料,名为“ 基本SimpleXML用法” ,它显示了基本遍历并还链接到更高级的xpath主题。

And don't forget when you output dynamic data into HTML to properly HTML encode it. 而且,不要忘记将动态数据输出到HTML中以正确地对其进行HTML编码的时间。 I've used the htmlspecialchars function for that, you need to provide the correct encoding parameters which I've left out for brevity in my answer. 我为此使用了htmlspecialchars函数,您需要提供正确的编码参数,为了简洁起见,我省略了这些参数。

Example in full: 完整示例:

<?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)));
    }
}

Exemplary output (plain-text): 示例输出(纯文本):

<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

Transliteration and Output Encoding with SimpleXML 使用SimpleXML进行音译和输出编码

One way to globally apply transliteration (removal of accents) and HTML encoding ( htmlspecialchars ) for every string-value of the SimpleXMLElement can be achieved by extending it. 通过扩展SimpleXMLElement的每个字符串值,可以采用一种全局应用音译(去除重音)和HTML编码( htmlspecialchars )的方法。 There is a shortcomming: a SimpleXMLElement can't have private properties (because the properties are all magic), however you can create static global variables. 有一个缺点: SimpleXMLElement不能具有私有属性(因为这些属性都是魔术),但是您可以创建静态全局变量。 For keeping the instance of a Transliterator this is enough. 为了保留音译器的实例,这就足够了。 And for manipulating the string values, the __toString() magic method works well with SimpleXMLElement : 为了处理字符串值, __toString()魔术方法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');
    }
}

All you need to do to benefit from the string manipulations is to either use this classname XMLTransliterated (or whichever you would name the class) when creating the SimpleXMLElement : 要从字符串操作中受益,您需要做的就是在创建SimpleXMLElement时使用此类名XMLTransliterated (或使用任何您要命名的类):

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

- or - and this is very special to simplexml, you can change the class later on with a little conversion trick: -或-这对于simplexml非常特殊,您可以稍后使用一些转换技巧来更改类:

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

This will make the following code use an XMLTransliterated instead of the previous less specific SimpleXMLElement so the code largely remains the same (please note that the htmlspecialchars and trim calls could be safely removed as they are now automatically called when accessing the string-values of the SimpleXMLElement ): 这将使以下代码使用XMLTransliterated而不是先前的不太具体的SimpleXMLElement,因此该代码在很大程度上保持不变(请注意,可以安全地删除htmlspecialcharstrim调用,因为现在访问它们的字符串值时会自动调用它们。 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);
    }
}

But the output will turn " Schloß " into " schloss ", " tôwn " into " town " and " provincé " into " province ". 但是输出将把“ Schloß ”变成“ schloss ”,“ tôwn ”变成“ town ”,“ provincé ”变成“ province ”。

Transliterator requires PHP 5.4 and you having the Intl extension enabled (which you should have, if not enable it). Transliterator需要PHP 5.4,并且您已启用了Intl扩展 (如果未启用,则应具有)。

Alternatively you can also make use of transliteration from the iconv library . 或者,您也可以使用iconv库中音译 But beware, this produces slightly different output: 但是请注意,这会产生稍微不同的输出:

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

More related transliteration questions: 更多相关的音译问题:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM