PHP / SimpleXML / XPath通过同一元素中的另一个属性获取属性值

时间:2013-12-01 22:57:51

标签: php xml xpath simplexml

我有这个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 值。

如果我遍历节点(like this question

,我可以使用SimpleXML
$resxml = simplexml_load_file('zip://my.pptx#ppt/slides/_rels/slide1.xml.rels');
echo $resxml->Relationship[0]->attributes()->Target;

但我想使用xpath using this sort of idea来获取它。无论我在xpath中做什么,当我搜索像'rId3'这样的东西时,都会返回一个空对象。我以为它将是下面的xpath语句,但它返回一个空对象。我尝试了大约50个组合,并在搜索时发现了许多相似但不完全相同的问题:

$image = $resxml->xpath("/Relationships/Relationship[@Id='rId3']/@Target"); 
print_r($image);

我想我最终会迭代遍历所有节点但看起来效率低下。我的服务器似乎在Dom可用和启用SimpleXML中有XPath。

2 个答案:

答案 0 :(得分:1)

谢谢。您的出色答案是我找到解决方案的关键。阅读完帖子后,我在Stack交换中的其他地方发现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);

答案 1 :(得分:0)

我认为你的问题可能是命名空间。 PPTX Relationship files使用命名空间“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()可以直接返回标量。

相关问题