使用PHP SimpleXML访问非默认名称空间元素属性

6ljaweal  于 2023-02-11  发布在  PHP
关注(0)|答案(2)|浏览(121)

API响应中有一些烦人的XML,如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><report><QueryResult>
  <ResumptionToken>123456</ResumptionToken>
  <IsFinished>true</IsFinished>
  <ResultXml>
    <rowset xmlns="urn:schemas-microsoft-com:xml-analysis:rowset">
      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:saw-sql="urn:saw-sql" targetNamespace="urn:schemas-microsoft-com:xml-analysis:rowset">
        <xsd:complexType name="Row">
          <xsd:sequence>
            <xsd:element maxOccurs="1" minOccurs="1" name="Column0" saw-sql:aggregationRule="none" saw-sql:aggregationType="nonAgg" saw-sql:columnHeading="0" saw-sql:displayFormula="0" saw-sql:length="4" saw-sql:precision="12" saw-sql:scale="0" saw-sql:tableHeading="" saw-sql:type="integer" type="xsd:int"/>
            <xsd:element maxOccurs="1" minOccurs="0" name="Column1" saw-sql:aggregationRule="none" saw-sql:aggregationType="nonAgg" saw-sql:columnHeading="ISBN" saw-sql:displayFormula=""Bibliographic Details"."ISBN"" saw-sql:length="255" saw-sql:precision="255" saw-sql:scale="0" saw-sql:tableHeading="Bibliographic Details" saw-sql:type="varchar" type="xsd:string"/>
            <xsd:element maxOccurs="1" minOccurs="0" name="Column2" saw-sql:aggregationRule="none" saw-sql:aggregationType="nonAgg" saw-sql:columnHeading="ISSN" saw-sql:displayFormula=""Bibliographic Details"."ISSN"" saw-sql:length="255" saw-sql:precision="255" saw-sql:scale="0" saw-sql:tableHeading="Bibliographic Details" saw-sql:type="varchar" type="xsd:string"/>
            <xsd:element maxOccurs="1" minOccurs="0" name="Column3" saw-sql:aggregationRule="none" saw-sql:aggregationType="nonAgg" saw-sql:columnHeading="Publication Date" saw-sql:displayFormula=""Bibliographic Details"."Publication Date"" saw-sql:length="255" saw-sql:precision="255" saw-sql:scale="0" saw-sql:tableHeading="Bibliographic Details" saw-sql:type="varchar" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:schema>
      <Row>
        <Column0>0</Column0>
        <Column1>55555555 444444445</Column1>
        <Column3>[2019]</Column3>

      </Row>
      <Row>
        <Column0>0</Column0>
        <Column1>555555555</Column1>
        <Column3>©2009.</Column3>
      </Row>

我正在使用PHP的SimpleXML来解析这些数据,但是很难访问位于xsd:element下的非默认名称空间中的列标题。saw-sql:columnHeading=“Publication Date”,因为该列可以是动态的,并不总是“Publication Date”。因此,我希望取出saw-sql[@columnHeading]的值。
我尝试了所有的方式来注册Xpath的名称空间,使用attributes()等,我得到的最接近的是:

$ResponseXml->registerXPathNamespace('xsd','http://www.w3.org/2001/XMLSchema');
$elements = $ResponseXml->xpath('//xsd:element[@minOccurs]');

这实际上为我提供了默认的命名空间属性,但我需要saw-sql的属性,以及相同的方法:

$ResponseXml->registerXPathNamespace('saw-sql','urn:saw-sql');
$elements = $ResponseXml->xpath('//saw-sql:element[@columnHeading]');

却没有任何结果。

oewdyzsn

oewdyzsn1#

XPath //saw-sql:element[@columnHeading]正在查找名为element的元素(在saw-sql名称空间中),这些元素具有名为columnHeading的属性(没有名称空间),但是元素名称实际上在xsd名称空间中,而属性 * 在saw-sql名称空间中。
所以我相信你想要的是:

$ResponseXml->registerXPathNamespace('xsd','http://www.w3.org/2001/XMLSchema');
$ResponseXml->registerXPathNamespace('saw-sql','urn:saw-sql');
$elements = $ResponseXml->xpath('//xsd:element[@saw-sql:columnHeading]');
sczxawaw

sczxawaw2#

例如,您可以使用DOMDocument而不是SimpleXML来解析它

<?php

$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><report><QueryResult>
  <ResumptionToken>123456</ResumptionToken>
  <IsFinished>true</IsFinished>
  <ResultXml>
    <rowset xmlns="urn:schemas-microsoft-com:xml-analysis:rowset">
      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:saw-sql="urn:saw-sql" targetNamespace="urn:schemas-microsoft-com:xml-analysis:rowset">
        <xsd:complexType name="Row">
          <xsd:sequence>
            <xsd:element maxOccurs="1" minOccurs="1" name="Column0" saw-sql:aggregationRule="none" saw-sql:aggregationType="nonAgg" saw-sql:columnHeading="0" saw-sql:displayFormula="0" saw-sql:length="4" saw-sql:precision="12" saw-sql:scale="0" saw-sql:tableHeading="" saw-sql:type="integer" type="xsd:int"/>
            <xsd:element maxOccurs="1" minOccurs="0" name="Column1" saw-sql:aggregationRule="none" saw-sql:aggregationType="nonAgg" saw-sql:columnHeading="ISBN" saw-sql:displayFormula=""Bibliographic Details"."ISBN"" saw-sql:length="255" saw-sql:precision="255" saw-sql:scale="0" saw-sql:tableHeading="Bibliographic Details" saw-sql:type="varchar" type="xsd:string"/>
            <xsd:element maxOccurs="1" minOccurs="0" name="Column2" saw-sql:aggregationRule="none" saw-sql:aggregationType="nonAgg" saw-sql:columnHeading="ISSN" saw-sql:displayFormula=""Bibliographic Details"."ISSN"" saw-sql:length="255" saw-sql:precision="255" saw-sql:scale="0" saw-sql:tableHeading="Bibliographic Details" saw-sql:type="varchar" type="xsd:string"/>
            <xsd:element maxOccurs="1" minOccurs="0" name="Column3" saw-sql:aggregationRule="none" saw-sql:aggregationType="nonAgg" saw-sql:columnHeading="Publication Date" saw-sql:displayFormula=""Bibliographic Details"."Publication Date"" saw-sql:length="255" saw-sql:precision="255" saw-sql:scale="0" saw-sql:tableHeading="Bibliographic Details" saw-sql:type="varchar" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:schema>
      <Row>
        <Column0>0</Column0>
        <Column1>55555555 444444445</Column1>
        <Column3>[2019]</Column3>

      </Row>
      <Row>
        <Column0>0</Column0>
        <Column1>555555555</Column1>
        <Column3>©2009.</Column3>
      </Row>
XML;
$domd = new DOMDocument();
@$domd->loadHTML($xml);
foreach ($domd->getElementsByTagName(strtolower("ResultXml")) as $resultXml) {
    $keyNames1 = [];
    $keyNames2 = [];
    foreach ($resultXml->getElementsByTagName("rowset") as $rowset) {
        foreach ($rowset->getElementsByTagName("sequence") as $sequence) {
            foreach ($sequence->getElementsByTagName("element") as $element) {
                $keyNames1[] = $element->getAttribute("name");
                $keyNames2[] = $element->getAttribute(strtolower("saw-sql:columnHeading"));
            }
        }
    }
    $rows = [];
    foreach ($resultXml->getElementsByTagName("row") as $row) {
        $rowData = [];
        foreach ($keyNames1 as $keyName1Key => $keyName1Name) {
            $tmp = $row->getElementsByTagName(strtolower($keyName1Name));
            if ($tmp->length) {
                $rowData[$keyNames2[$keyName1Key]] = $tmp->item(0)->textContent;
            }
        }
        $rows[] = $rowData;
    }
    var_export($rows);
}

收益率

array (
  0 =>
  array (
    0 => '0',
    'ISBN' => '55555555 444444445',
    'Publication Date' => '[2019]',
  ),
  1 =>
  array (
    0 => '0',
    'ISBN' => '555555555',
    'Publication Date' => '©2009.',
  ),
)
  • 我使用loadHTML而不是loadXML,因为DOMDocument坚持您的XML不是有效的XML;在loadHTML()模式下,由于某种原因,所有内容都是小写,而在loadXML()模式下,所有内容都区分大小写。

相关问题