【问题标题】:Printing content of a XML file using XML DOM使用 XML DOM 打印 XML 文件的内容
【发布时间】:2011-01-04 21:04:51
【问题描述】:

我有一个简单的 XML 文档:

<?xml version="1.0"?>
<cellphones>
  <telefon>
    <model>Easy DB</model>
    <proizvodjac>Alcatel</proizvodjac>
    <cena>25</cena>
  </telefon>
  <telefon>
    <model>3310</model>
    <proizvodjac>Nokia</proizvodjac>
    <cena>30</cena>
  </telefon>
  <telefon>
    <model>GF768</model>
    <proizvodjac>Ericsson</proizvodjac>
    <cena>15</cena>
  </telefon>
  <telefon>
    <model>Skeleton</model>
    <proizvodjac>Panasonic</proizvodjac>
    <cena>45</cena>
  </telefon>
  <telefon>
    <model>Earl</model>
    <proizvodjac>Sharp</proizvodjac>
    <cena>60</cena>
  </telefon>
</cellphones>

我需要使用 XML DOM 打印这个文件的内容,它需要这样的结构:

"model: Easy DB
proizvodjac: Alcatel
cena: 25"

对于 XML 中的每个节点。

必须使用 XML DOM 来完成。那就是问题所在。我可以用通常的简单方法来做。但这让我很困扰,因为我似乎无法在互联网上找到任何解决方案。

这是我能做到的,但我需要访问内部节点(子节点)并获取节点值。我还想摆脱一些突然出现的奇怪字符串“#text”。

<?php
    //kreira se DOMDocument objekat
    $xmlDoc = new DOMDocument();

    //u xml objekat se ucitava xml fajl
    $xmlDoc->load("poruke.xml");

    //dodeljuje se promenljivoj koreni element
    $x = $xmlDoc->documentElement;

    //prolazi se kroz petlju tako sto se ispisuje informacija o podelementima
    foreach ($x->childNodes AS $item){
        print $item->nodeName . " = " . $item->nodeValue . "<br />";
    }
?>

谢谢

【问题讨论】:

    标签: php xml dom


    【解决方案1】:

    奇怪的#text 字符串的解释

    奇怪的#text 字符串不是突然出现的,而是实际的文本节点。当您加载带有 DOM 任何空格的格式化 XML 文档时,例如默认情况下,缩进、换行和节点值将作为 DOMText 实例作为 DOM 的一部分,例如

    <cellphones>\n\t<telefon>\n\t\t<model>Easy DB…
    E           T   E        T     E      T      
    

    其中 E 是 DOMElement,T 是 DOMText

    要解决这个问题,请像这样加载文档:

    $dom = new DOMDocument;
    $dom->preserveWhiteSpace = FALSE;
    $dom->load('file.xml');
    

    那么你的文档结构如下

    <cellphones><telefon><model>Easy DB…
    E           E        E      T
    

    请注意,代表 DOMElement 值的各个节点仍将是 DOMText 实例,但控制格式的节点已消失。稍后会详细介绍。

    证明

    您可以使用以下代码轻松测试:

    $dom = new DOMDocument;
    $dom->preserveWhiteSpace = TRUE; // change to FALSE to see the difference
    $dom->load('file.xml');
    foreach ($dom->getElementsByTagName('telefon') as $telefon) {
        foreach($telefon->childNodes as $node) {
            printf(
                "Name: %s - Type: %s - Value: %s\n",
                $node->nodeName,
                $node->nodeType,
                urlencode($node->nodeValue)
            );
        }
    }
    

    此代码遍历给定 XML 中的所有 telefon 元素,并打印出节点名称、类型和它的子节点的 urlencoded 节点值。当你保留空白时,你会得到类似的东西

    Name: #text - Type: 3 - Value: %0A++++
    Name: model - Type: 1 - Value: Easy+DB
    Name: #text - Type: 3 - Value: %0A++++
    Name: proizvodjac - Type: 1 - Value: Alcatel
    Name: #text - Type: 3 - Value: %0A++++
    Name: cena - Type: 1 - Value: 25
    Name: #text - Type: 3 - Value: %0A++
    …
    

    我对值进行 urlencoded 的原因是为了表明实际上存在 DOMText 节点,其中包含 DOMDocument 中的缩进和换行符。 %0A 是一个换行符,而每个 + 是一个空格。

    当您将其与您的 XML 进行比较时,您会看到在每个 &lt;telefon&gt; 元素之后有一个换行符,后跟四个空格,直到 &lt;model&gt; 元素开始。同样,在结束&lt;cena&gt; 和开始&lt;telefon&gt; 之间只有一个换行符和两个空格。

    这些节点的给定类型是 3,即 - according to the list of predefined constants - 是 XML_TEXT_NODE,例如DOMText 节点。由于缺少正确的元素名称,这些节点的名称为#text。

    忽略空格

    现在,当您禁用保留空白时,上面将输出:

    Name: model - Type: 1 - Value: Easy+DB
    Name: proizvodjac - Type: 1 - Value: Alcatel
    Name: cena - Type: 1 - Value: 25
    Name: model - Type: 1 - Value: 3310
    …
    

    如您所见,没有更多的#text 节点,而只有type 1 节点,这意味着XML_ELEMENT_NODE,例如DOMElement

    DOMElements 包含 DOMText 节点

    我一开始说过,DOMElements 的值也是DOMText 实例。但是在上面的输出中,它们无处可寻。那是因为我们正在访问nodeValue 属性,该属性将DOMText 的值作为字符串返回。我们可以很容易地证明该值为DOMText

    $dom = new DOMDocument;
    $dom->preserveWhiteSpace = FALSE;
    $dom->loadXML($xml);
    foreach ($dom->getElementsByTagName('telefon') as $telefon) {
        $node = $telefon->firstChild->firstChild; // 1st child of model
        printf(
            "Name: %s - Type: %s - Value: %s\n",
            $node->nodeName,
            $node->nodeType,
            urlencode($node->nodeValue)
        );
    }
    

    会输出

    Name: #text - Type: 3 - Value: Easy+DB
    Name: #text - Type: 3 - Value: 3310
    Name: #text - Type: 3 - Value: GF768
    Name: #text - Type: 3 - Value: Skeleton
    Name: #text - Type: 3 - Value: Earl
    

    这证明DOMElement 包含它的值,因为DOMTextnodeValue 只是直接返回DOMText 的内容。

    更多关于 nodeValue

    事实上,nodeValue 足够聪明,可以连接任何DOMText 子项的内容:

    $dom = new DOMDocument;
    $dom->loadXML('<root><p>Hello <em>World</em>!!!</p></root>');
    $node = $dom->documentElement->firstChild; // p
    printf(
        "Name: %s - Type: %s - Value: %s\n",
        $node->nodeName,
        $node->nodeType,
        $node->nodeValue
    );
    

    会输出

    Name: p - Type: 1 - Value: Hello World!!!
    

    虽然这些确实是

    DOMText "Hello"
    DOMElement em with DOMText "World"
    DOMText "!!!"
    

    使用 XML DOM 打印 XML 文件的内容

    要最终回答您的问题,请查看第一个测试代码。你需要的一切都在里面。当然,现在你也得到了很好的其他答案。

    【讨论】:

    • 我喜欢其他答案,因为它们可以快速轻松地帮助我,但还有更多,我无法表达我对这个解释的欣赏程度。真是太棒了,非常感谢!
    【解决方案2】:

    在我看来你想要这样的东西:

    <?php
    
    $dom = new DOMDocument();
    $dom->load("poruke.xml");
    
    $telefon = $dom->getElementsByTagName('telefon');
    
    foreach ($telefon as $t) {
        print "model: " . $t->childNodes->item(0)->nodeValue . "\n" .
              "proizvodjac: " . $t->childNodes->item(1)->nodeValue . "\n" . 
              "cena: " . $t->childNodes->item(2)->nodeValue;
    }
    

    就格式而言,这可能不是您所需要的,但它应该向您大致展示您需要做什么。

    【讨论】:

      【解决方案3】:

      这是经过尝试和测试的解决方案。

      <?php
      
          $xmlDoc = new DOMDocument();
      
          $xmlDoc->load("mobiles.xml");
      
          $x = $xmlDoc->documentElement;
      
          $telefons = $x->getElementsByTagName( "telefon" );
      
          foreach( $telefons as $telefon )
        {
      
            $model = $telefon->getElementsByTagName( "model" );
      
            $proiz = $telefon->getElementsByTagName( "proizvodjac" );
      
            $cena = $telefon->getElementsByTagName( "cena" );
      
      
        echo $model->item(0)->nodeName .': '. $model->item(0)->nodeValue.' <br> '.$proiz->item(0)->nodeName .':'.$proiz->item(0)->nodeValue.'<br> '.$cena->item(0)->nodeName.':'.$cena->item(0)->nodeValue.' <br><br>';
      
        }
      
      
      ?>
      

      【讨论】:

        【解决方案4】:

        试试这个

        $xmlDoc = new DOMDocument();
        
        $dom->load("poruke.xml");
        
        // Load the DomDoc into an Xpath object, you can then query it
        $xpath = new DOMXpath($xmlDoc);
        
        // Find all telefon elements
        $result = $xpath->query("//telefon");
        
        // For each telefon item found
        foreach ($result AS $item){
            // For each child node of the telefon element print the nodeName and nodeValue
            foreach($item->childNodes as $node){
                echo $node->nodeName . " = " . $node->nodeValue . " <br />";
            }
        }
        

        【讨论】:

        • 始终牢记 XPath,这太棒了。它将使您的代码保持干净,并使在 XML 和 HTML 中查找元素比数组混搭更容易
        • 虽然我同意 XPath 非常棒(对于复杂查询),但应该注意的是,与仅使用 getElementsByTagName 相比,OP 从这个特定查询中没有任何收获。此外,除非您使用 preserveWhitespace = FALSE 加载 XML,否则在遍历子节点时还将打印 DOMText 节点。
        【解决方案5】:

        找到了一个很简单的方法:

        $xml = $domElement->ownerDocument->saveXML($domElement);
        

        或者如果您已经将文档保存在变量中。

        $xml = $document->saveXML($domElement);
        

        解决方案位于: http://php.net/manual/fr/class.domelement.php

        【讨论】:

          猜你喜欢
          • 2019-12-15
          • 2016-08-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-23
          • 2021-01-26
          • 2013-03-20
          • 2021-09-23
          相关资源
          最近更新 更多