代码之家  ›  专栏  ›  技术社区  ›  thomasrutter

如何在phpdom中找到元素的名称空间?

  •  6
  • thomasrutter  · 技术社区  · 15 年前

    这听起来是个很容易回答的问题,但我一直没能让它起作用。我正在运行PHP5.2.6。

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
    ...
    

    但是,我在PHP中找不到任何编程方式来查看该名称空间。我希望能够检查它是否存在以及它的设置。

    检查 $document->documentElement->namespaceURI 这是显而易见的答案,但它是空的(我从来没有真正能够得到非空的)。是什么在输出中生成xmlns值,我如何读取它?

    编辑:

    3 回复  |  直到 13 年前
        1
  •  5
  •   Community Mohan Dere    9 年前

    Like edorian already showed ,则在使用 loadXML . 但您是对的,对于加载了 loadHTML :

    $html = <<< XML
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="foo" lang="en">
        <body xmlns="foo">Bar</body>
    </html>
    XML;
    
    $dom = new DOMDocument;
    $dom->loadHTML($html);
    
    var_dump($dom->documentElement->getAttribute("xmlns"));
    var_dump($dom->documentElement->lookupNamespaceURI(NULL));
    var_dump($dom->documentElement->namespaceURI);
    

    将产生空结果。但是可以使用XPath

    $xp = new DOMXPath($dom);
    echo $xp->evaluate('string(@xmlns)');
    // http://www.w3.org/1999/xhtml;
    

    echo $xp->evaluate('string(body/@xmlns)'); // foo
    

    或使用上下文节点

    $body = $dom->documentElement->childNodes->item(0);
    echo $xp->evaluate('string(@xmlns)', $body);
    // foo
    

    真实的 libxml uses a different module to parse HTML

    var_dump($dom->nodeType); // 13 with loadHTML, 9 with loadXml
    

    13岁的孩子 XML_HTML_DOCUMENT_NODE .

        2
  •  3
  •   edorian    15 年前

    <?php
    $xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?'.
           '><html xmlns="http://www.w3.org/1999/xhtml" lang="en"></html>';
    $x = DomDocument::loadXml($xml);
    var_dump($x->documentElement->getAttribute("xmlns"));
    var_dump($x->documentElement->lookupNamespaceURI(NULL));
    

    string(28) "http://www.w3.org/1999/xhtml"
    string(28) "http://www.w3.org/1999/xhtml"
    

    希望这就是你的要求:)

        3
  •  1
  •   ircmaxell    15 年前

    好吧,你可以用这样的函数:

    function getNamespaces(DomNode $node, $recurse = false) {
        $namespaces = array();
        if ($node->namespaceURI) {
            $namespaces[] = $node->namespaceURI;
        }
        if ($node instanceof DomElement && $node->hasAttribute('xmlns')) {
            $namespaces[] = $xmlns = $node->getAttribute('xmlns');
            foreach ($node->attributes as $attr) {
                if ($attr->namespaceURI == $xmlns) {
                    $namespaces[] = $attr->value;
                    }
            }
        }
        if ($recurse && $node instanceof DomElement) {
            foreach ($node->childNodes as $child) {
                $namespaces = array_merge($namespaces, getNamespaces($child, vtrue));
            }
        }
        return array_unique($namespaces);
    }
    

    所以,你给它一个DomEelement,然后它会找到所有相关的名称空间:

    $xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <html xmlns="http://www.w3.org/1999/xhtml" 
             lang="en" 
             xmlns:foo="http://example.com/bar">
               <body>
                    <h1>foo</h1>
                    <foo:h2>bar</foo:h2>
               </body>
     </html>';
    var_dump(getNamespaces($dom->documentElement, true));
    

    array(2) {
      [0]=>
      string(28) "http://www.w3.org/1999/xhtml"
      [3]=>
      string(22) "http://example.com/bar"
    }
    

    请注意,DomDocument将自动删除所有未使用的名称空间。。。

    至于为什么 $dom->documentElement->namespaceURI null ,这是因为document元素没有名称空间。这个 xmlns 属性为文档提供了一个默认名称空间,但它不赋予 html 带有名称空间的标记(用于DOM交互)。你可以试试看 $dom->documentElement->removeAttribute('xmlns')