doumu6941 2015-03-08 17:00
浏览 61
已采纳

使用php迭代XML文件

I have an XML file with the following:

<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. 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.

  • 写回答

2条回答 默认 最新

  • dongzhang6677 2015-03-08 20:09
    关注

    You have not shared the complete XML structure so it's unclear where the root of the document is (the document element).

    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:

    $xml = simplexml_load_file('example.xml');
    
    foreach ($xml->property as $property) {
        printf(
            "<h1>%s for sale in %s, %s</h1>
    ", 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. You can, but you don't need to. Just saying.

    Now you're looking for the image URLs. Each <property> element has a single child element named <images> and these again have mulitple <url> elements you're interested in.

    This can be done with an xpath query (as you go down deeper more than one level):

    $urls = $property->xpath('images/image/url');
    foreach ($urls as $url) {
        printf(" - %s
    ", 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. Just as a counter-example:

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

    I hope this shows you more well how the traversal works in 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.

    And don't forget when you output dynamic data into HTML to properly HTML encode it. 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.

    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>
    ",
            htmlspecialchars($property->id), htmlspecialchars($property->town), htmlspecialchars($property->province)
        );
    
        $urls = $property->xpath('images/image/url');
        foreach ($urls as $url) {
            printf(" - %s
    ", 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

    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. There is a shortcomming: a SimpleXMLElement can't have private properties (because the properties are all magic), however you can create static global variables. For keeping the instance of a Transliterator this is enough. And for manipulating the string values, the __toString() magic method works well with 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:

    $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:

    $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):

    $xml = simplexml_load_string($buffer, 'XMLTransliterated');
    
    foreach ($xml->property as $property) {
        printf(
            "<h1>%s (%s) for sale in %s, %s</h1>
    ",
            $property->id, $property->type, $property->town, $property->province
        );
    
        $urls = $property->xpath('images/image/url');
        foreach ($urls as $url) {
            printf(" - %s
    ", $url);
        }
    }
    

    But the output will turn "Schloß" into "schloss", "tôwn" into "town" and "provincé" into "province".

    Transliterator requires PHP 5.4 and you having the Intl extension enabled (which you should have, if not enable it).

    Alternatively you can also make use of transliteration from the iconv library. But beware, this produces slightly different output:

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

    More related transliteration questions:

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 MATLAB怎么通过柱坐标变换画开口是圆形的旋转抛物面?
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题
  • ¥15 Visual Studio问题
  • ¥20 求一个html代码,有偿