PHP:从名称中逐个节点获取值(名称空间问题)

时间:2014-08-20 08:03:23

标签: php xml xml-parsing

我从外部服务收到了这些xml:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href=(...)?>
<pos:Document xmlns:pos=(...) xmlns:str=(...) xmlns:xsi=(...) xsi:schemaLocation=(...)>
  <pos:DescribeDocument>
    (...)
  </pos:DescribeDocument>
  <pos:UPP>
    (...)
  </pos:UPP>
  <ds:Signature Id="ID-9326" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo Id="ID-9325" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:pos="adress" xmlns:str="adress" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        (...)
    </ds:SignedInfo>
    <ds:Object>
        <xades:QualifyingProperties Id="ID-9337a6d1" Target="#ID-932668c0-d4f9-11e3-bb2d-001a645ad128" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#">
            <xades:SignedProperties Id="ID-9337a6d0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:pos="adress" xmlns:str="adress" xmlns:xades="adress" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <xades:SignedSignatureProperties>
                    <xades:SigningTime>sometime</xades:SigningTime>
                    <xades:SigningCertificate>
                        <xades:Cert>
                            <xades:CertDigest>
                                <ds:DigestMethod Algorithm="adress"/>
                                <ds:DigestValue>someValue</ds:DigestValue>
                            </xades:CertDigest>
                            <xades:IssuerSerial>
                                <ds:X509IssuerName>CNsomeValue</ds:X509IssuerName>
                                <ds:X509SerialNumber>SerialsomeValue</ds:X509SerialNumber>
                            </xades:IssuerSerial>
                        </xades:Cert>
                    </xades:SigningCertificate>
                    <xades:SignaturePolicyIdentifier>
                        <xades:SignaturePolicyImplied/>
                    </xades:SignaturePolicyIdentifier>
                </xades:SignedSignatureProperties>
                <xades:SignedDataObjectProperties>
                    <xades:DataObjectFormat ObjectReference="#ID-93257e60">

                        <xades:Description>NEEDVALUE</xades:Description>

                    </xades:DataObjectFormat>
                </xades:SignedDataObjectProperties>
            </xades:SignedProperties>
        </xades:QualifyingProperties>
    </ds:Object>
  </ds:Signature>
</pos:Document>

它有一些命名空间。而且我必须获得价值。 我写了一些代码,但没有任何作用:

$xmlFileContent = file_get_contents($pathToXML);
$dom = new SimpleXMLElement($xmlFileContent, LIBXML_COMPACT);

$namespaces = $dom->getNamespaces(true);
foreach ($namespaces as $key => $namespace) {
    $dom->registerXPathNamespace($key, $namespace);
}
$matches = $dom->xpath('//xades:Description'); //no success

$doms = new DOMDocument;
$doms->loadXML($path);
foreach($doms->getElementsByTagNameNS($namespaces['xades'],'*') as $element){
    echo 'local name: ', $element->localName, ', prefix: ', $element->prefix, "\n";          //no success
}    

你能帮助我到达这些节点(xades:Description)吗?

PS: 我也用它(但没有成功):

$result1 = $dom->xpath('/Dokument/ds:Signature/ds:Object/xades:QualifyingProperties/xades:SignedProperties/xades:SignedDataObjectProperties/xades:DataObjectFormat/xades:Description');

2 个答案:

答案 0 :(得分:2)

您从XML中删除了命名空间定义。如果你看到像&x; xmlns:xades&#39;这样的属性。实际的命名空间是该属性的值。它在当前上下文中为该命名空间定义了别名/前缀。大多数时候URL用作命名空间标识符(因为它避免了潜在的冲突)。但是像urn:somestring这样的值是有效的。

您还需要在DOMXpath对象上为命名空间注册前缀。此前缀不需要与文档中的前缀相同。以这种方式看待它:

DOMDocument将节点名称从prefix:Description解析为{namespace-uri}:Description

DOMXpath使用自己的定义以相同的方式解析Xpath表达式中的节点名称。例如//prefix:Description//{namespace-uri}:Description。然后它比较已解析的名称。

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
$xpath->registerNamespace('x', 'urn:xades');
var_dump($xpath->evaluate('string(//x:Description)'));

输出:https://eval.in/181304

string(9) "NEEDVALUE"

答案 1 :(得分:0)

通过修改XPath以忽略命名空间,可能有解决方法,以防您无法找到正确的解决方案

$result = $dom->xpath('//*[local-name() = "Description"]');