我有这个XML(来自pptx文件):
<Relationships>
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image2.png"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image1.wmf"/>
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout1.xml"/>
</Relationships>
我想从Relationship元素中提取Target属性,并且我知道Id值。
如果我遍历节点(像这个问题一样),我可以用SimpleXML来完成它
$resxml = simplexml_load_file('zip://my.pptx#ppt/slides/_rels/slide1.xml.rels');
echo $resxml->Relationship[0]->attributes()->Target;
但我想使用xpath,使用这种想法来获得它。当我搜索类似"rId3"的东西时,无论我在xpath中做什么,都会返回一个空对象。我原以为是下面的xpath语句,但它返回了一个空对象。我尝试了大约50种组合,在搜索时发现了很多相似但不完全相同的问题:
$image = $resxml->xpath("/Relationships/Relationship[@Id='rId3']/@Target");
print_r($image);
我想我最终会遍历所有节点,但这似乎效率很低。我的服务器似乎在Dom中有XPath可用,并且启用了SimpleXML。
谢谢。你出色的回答是我找到解决方案的关键。在阅读了您的文章后,我在Stack exchange的其他地方发现SimpleXML删除了第一个节点上的名称空间属性。我考虑了名称空间作为问题,但在查看树时只查看了simpleXML输出。你在看真正的来源时把我说对了。
我仅使用简单XML的解决方案如下:
$resxml->registerXPathNamespace('r', 'http://schemas.openxmlformats.org/package/2006/relationships');
$image = $resxml->xpath("/r:Relationships/r:Relationship[@Id='rId3']/@Target");
print_r($image);
我认为问题可能是命名空间。PPTX关系文件使用命名空间"http://schemas.microsoft.com/package/2005/06/relationships"。但是SimpleXmls-xpath也有它自己的魔力。如果文件包含命名空间(检查源),你必须为它注册一个自己的前缀。
$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Relationships
xmlns="http://schemas.microsoft.com/package/2005/06/relationships">
<Relationship Id="rId1"
Type="http://schemas.microsoft.com/office/2006/relationships/image"
Target="http://en.wikipedia.org/images/wiki-en.png"
TargetMode="External" />
<Relationship Id="rId2"
Type="http://schemas.microsoft.com/office/2006/relationships/hyperlink"
Target="http://www.wikipedia.org"
TargetMode="External" />
</Relationships>
XML;
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
$xpath->registerNamespace('r', 'http://schemas.microsoft.com/package/2005/06/relationships');
var_dump(
$xpath->evaluate("string(/r:Relationships/r:Relationship[@Id='rId2']/@Target)", NULL, FALSE)
);
输出:
string(24) "http://www.wikipedia.org"
Xpath不知道类似默认名称空间的东西。如果没有前缀,则可以查找没有任何命名空间的元素。如果没有显式前缀,则属性没有命名空间。
为了消除混淆,PHP函数(SimpleXMLElement::xpath()、DOMXpath::query()和DOMXpath::evaluate())会自动注册所用上下文的命名空间定义。第三个参数允许禁用这种行为。
与其他两个函数不同,DOMXpath::evaluate()可以直接返回标量。