使用XPATH和PHP DOM选择和删除节点时出现的问题
可能是个愚蠢的问题,但到目前为止我还没弄明白 我有一个XHTML文档作为字符串。它在使用XPATH和PHP DOM选择和删除节点时出现的问题,php,xpath,domdocument,Php,Xpath,Domdocument,可能是个愚蠢的问题,但到目前为止我还没弄明白 我有一个XHTML文档作为字符串。它在$temp中,到目前为止还不错。我想做两件事。我想选择正文中的所有元标记(它们之所以存在是因为它们与微数据一起使用),然后删除它们。删除已删除的微数据属性后 $xml=new DOMDocument(); $xml->loadXML($temp); $xpath = new DOMXPath($xml); $attr = $xpath->query("//@itemsc
$temp
中,到目前为止还不错。我想做两件事。我想选择正文中的所有元标记(它们之所以存在是因为它们与微数据一起使用),然后删除它们。删除已删除的微数据属性后
$xml=new DOMDocument();
$xml->loadXML($temp);
$xpath = new DOMXPath($xml);
$attr = $xpath->query("//@itemscope|//@itemprop|//@itemtype|//@itemid|//@itemref");
foreach ($attr as $entry)
$entry->parentNode->removeAttribute($entry->nodeName);
这很有效。但我无法使用Xpath选择任何节点
$xpath = new DOMXPath($xml); // thought I had to update this after changing the XML
echo $xpath->query("//body")->length; // => 0
echo $xml->getElementsByTagName("body")->length; // => 1
问题1:如何使用Xpath选择节点。为什么这样不行
这可用于获取节点列表,但:
$node = $xml->getElementsByTagName("body")->item(0)->getElementsByTagName("meta");
我想用以下方法删除节点:(类似于删除上面的属性)
但节点仍然存在
因此,问题2:如何从XML文件中删除节点
特别是任何实体节点中的任意元节点
谢谢
更新
让我添加一个HTML测试用例:
$temp='<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<meta charset="utf-8"/>
</head>
<body id="dok" itemscope="itemscope" itemtype="http://schema.org/WebPage" >
<div><div><div><meta itemprop="dummy" content="something"/></div></div></div>
<span><meta itemprop="dummy2" content="something2"/></span>
</body>
</html>';
不带名称空间的解决方案
这是关于xmlns=”http://www.w3.org/1999/xhtml“
名称空间始终位于根html
标记中//body
选择任何不属于任何命名空间的body标记。因为我们确实指定了一个默认名称空间,并且body
是该名称空间的一部分,所以//body
不会选择它。我不知道用什么名称访问XHTML固有的名称空间,而不在名称下声明它,但是如果我们在创建XML之前去掉它,一切都很好。完成后,我们可以将其添加回
$temp = str_replace('xmlns="http://www.w3.org/1999/xhtml"','',$temp);
$xml=new DOMDocument();
$xml->loadXML($temp);
$xpath = new DOMXPath($xml);
$attr = $xpath->query("//@itemscope|//@itemprop|//@itemtype|//@itemid|//@itemref");
foreach ($attr as $entry)
$entry->parentNode->removeAttribute($entry->nodeName);
$node = $xpath->query("//body//meta");
foreach ($node as $entry)
{
$entry->parentNode->removeChild($entry);
}
$temp=$xml->saveXML();
$temp = str_replace('<html','<html xmlns="http://www.w3.org/1999/xhtml"',$temp);
$temp=str\u replace('xmlns='http://www.w3.org/1999/xhtml“,”,“$temp);
$xml=newdomdocument();
$xml->loadXML($temp);
$xpath=newdomxpath($xml);
$attr=$xpath->query(“/@itemscope |/@itemprop |/@itemtype |//@itemid |/@itemref”);
foreach($attr作为$entry)
$entry->parentNode->removeAttribute($entry->nodeName);
$node=$xpath->query(“//body//meta”);
foreach($node作为$entry)
{
$entry->parentNode->removeChild($entry);
}
$temp=$xml->saveXML();
$temp=str_replace(“这段代码为我完成了这项工作:
$temp='<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<meta charset="utf-8"/>
</head>
<body id="dok" itemscope="itemscope" itemtype="http://schema.org/WebPage" >
<div><div><div><meta itemprop="dummy" content="something"/></div></div></div>
<span><meta itemprop="dummy2" content="something2"/></span>
</body>
</html>';
$xml=new DOMDocument();
$xml->loadHtml($temp);
$xpath = new DOMXPath($xml); // thought I had to update this after changing the XML
$path = "//body//meta";
echo $xpath->query($path)->length, "\n"; # 2
foreach ($xpath->query($path) as $entry)
{
$entry->parentNode->removeChild($entry);
}
echo $xpath->query($path)->length, "\n"; # 0
这将以XML的形式加载文档,然后从文档中为xpath对象注册名称为xhtml
的名称空间URI
然后修改xpath查询以正确反映元素表达式的名称空间。让我猜猜:您有一个XHTML文档?@Tomalak是的,我有一个XHTML文档作为字符串,但输入错误严重:-),因此我修复了它。您可以试着使用$xml->loadHTML($temp)
,它甚至可以很好地加载格式错误的内容。Q1A:应该有效//body
在我看来不错,您可以尝试//head/meta
以及通过xpath直接访问meta元素。@hakre XHTML作为应用程序/xml使用,格式没有错误。loadXML应该可以//body
对我不起作用,元标记在body中。。。我用一个虚拟的$temp
更新了这个问题<代码>echo$xpath->query(“//head”)->长度代码>不适用于示例,但echo$xpath->query(“/@charset”)->长度代码>工作正常。这是XPath最大的常见问题:XHTML元素位于XHTML名称空间(通常用作默认名称空间)中,但在XPath表达式中,您尝试使用“无名称空间”中的名称访问元素。您需要注册绑定了前缀(比如“x:”)的XHTML名称空间。使用:x:body
而不是body
@hakre-Ah我看到我们同时解决了这个问题。没有明确的工作空间,任何事情都无法工作。。。我不知道。问题是,如果XHTML文档没有xmlns=”http://www.w3.org/1999/xhtml“
在它的根html
元素中,则不需要这样做。因此,如果输入文档发生更改,仍然使用loadHtml()可能更安全代码>。我想知道如何将一个名称空间注册为默认名称空间。@hakre它确实有xmlns=”http://www.w3.org/1999/xhtml“
在它的根html
元素中,它总是这样做。。。即使是上面的虚拟$temp
html也拥有它…@hakre它是另一种方式!不是缺少xmlns=”http://www.w3.org/1999/xhtml“
但它的存在首先是导致问题的原因。。。请参见我对问题的补充,即如何不使用名称空间和纯//body//meta
@C.O。您误解了我,这是假设性的:如果它不包含名称空间,那么所有元素都在默认名称空间中。你甚至很快就采纳了:正如我所写的,如果文档不包含这个字符串。您可以将其从文档中删除以实现此目的。瞧。这不是问题,而是xpath的工作方式。如果文档包含名称空间,则需要使用xpath注册它。如果删除了该名称空间(就像现在一样),那么默认名称空间将应用于文档中所有没有名称空间的元素,并且不需要为xpath注册名称空间。
$temp = str_replace('xmlns="http://www.w3.org/1999/xhtml"','',$temp);
$xml=new DOMDocument();
$xml->loadXML($temp);
$xpath = new DOMXPath($xml);
$attr = $xpath->query("//@itemscope|//@itemprop|//@itemtype|//@itemid|//@itemref");
foreach ($attr as $entry)
$entry->parentNode->removeAttribute($entry->nodeName);
$node = $xpath->query("//body//meta");
foreach ($node as $entry)
{
$entry->parentNode->removeChild($entry);
}
$temp=$xml->saveXML();
$temp = str_replace('<html','<html xmlns="http://www.w3.org/1999/xhtml"',$temp);
$temp='<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<meta charset="utf-8"/>
</head>
<body id="dok" itemscope="itemscope" itemtype="http://schema.org/WebPage" >
<div><div><div><meta itemprop="dummy" content="something"/></div></div></div>
<span><meta itemprop="dummy2" content="something2"/></span>
</body>
</html>';
$xml=new DOMDocument();
$xml->loadHtml($temp);
$xpath = new DOMXPath($xml); // thought I had to update this after changing the XML
$path = "//body//meta";
echo $xpath->query($path)->length, "\n"; # 2
foreach ($xpath->query($path) as $entry)
{
$entry->parentNode->removeChild($entry);
}
echo $xpath->query($path)->length, "\n"; # 0
$xml->loadXml($temp);
$xpath = new DOMXPath($xml);
$xpath->registerNamespace('xhtml', 'http://www.w3.org/1999/xhtml');
$path = "//xhtml:body//xhtml:meta";