【问题标题】:can't figure out SimpleXML syntax无法弄清楚 SimpleXML 语法
【发布时间】:2013-11-20 17:40:27
【问题描述】:

我正在尝试从soap 请求XML 日志中解析一些项目,但似乎无法弄清楚如何进入SimpleXMLElement 的内部。这是我正在使用的 XML 示例:

<?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://fedex.com/ws/rate/v9">
     <SOAP-ENV:Body>
      <ns1:RateRequest>
       <ns1:WebAuthenticationDetail>
        <ns1:UserCredential>
         <ns1:Key>aaaaaaaaaaa</ns1:Key>
         <ns1:Password>aaaaaaaaaaaaaaaaaaa</ns1:Password>
        </ns1:UserCredential>
       </ns1:WebAuthenticationDetail>
       <ns1:ClientDetail>
        <ns1:AccountNumber>11111111</ns1:AccountNumber>
        <ns1:MeterNumber>88888888</ns1:MeterNumber>
       </ns1:ClientDetail>
       <ns1:TransactionDetail>
        <ns1:CustomerTransactionId>1</ns1:CustomerTransactionId>
       </ns1:TransactionDetail>
       <ns1:Version>
        <ns1:ServiceId>crs</ns1:ServiceId>
        <ns1:Major>9</ns1:Major>
        <ns1:Intermediate>0</ns1:Intermediate>
        <ns1:Minor>0</ns1:Minor>
       </ns1:Version>
       <ns1:ReturnTransitAndCommit>true</ns1:ReturnTransitAndCommit>
       <ns1:RequestedShipment>
        <ns1:ShipTimestamp>2013-08-06T12:39:26-04:00</ns1:ShipTimestamp>
        <ns1:DropoffType>REGULAR_PICKUP</ns1:DropoffType>
        <ns1:Shipper>
         <ns1:AccountNumber>11111111</ns1:AccountNumber>
         <ns1:Address>
          <ns1:StreetLines>24 Seaview Blvd</ns1:StreetLines>
          <ns1:City>Port Washington</ns1:City>
          <ns1:StateOrProvinceCode>NY</ns1:StateOrProvinceCode>
          <ns1:PostalCode>11050</ns1:PostalCode>
          <ns1:CountryCode>US</ns1:CountryCode>
         </ns1:Address>
        </ns1:Shipper>
        <ns1:Recipient>
         <ns1:Address>
          <ns1:StreetLines>1234 Fifth Street</ns1:StreetLines>
          <ns1:City>Sixton</ns1:City>
          <ns1:StateOrProvinceCode>AR</ns1:StateOrProvinceCode>
          <ns1:PostalCode>72712</ns1:PostalCode>
          <ns1:CountryCode>US</ns1:CountryCode>
         </ns1:Address>
        </ns1:Recipient>
        <ns1:ShippingChargesPayment>
         <ns1:Payor>
          <ns1:AccountNumber>11111111</ns1:AccountNumber>
          <ns1:CountryCode>US</ns1:CountryCode>
         </ns1:Payor>
        </ns1:ShippingChargesPayment>
        <ns1:RateRequestTypes>ACCOUNT</ns1:RateRequestTypes>
        <ns1:PackageCount>1</ns1:PackageCount>
        <ns1:PackageDetail>INDIVIDUAL_PACKAGES</ns1:PackageDetail>
        <ns1:RequestedPackageLineItems>
         <ns1:Weight>
          <ns1:Units>LB</ns1:Units>
          <ns1:Value>14</ns1:Value>
         </ns1:Weight>
         <ns1:Dimensions>
          <ns1:Length>20</ns1:Length>
          <ns1:Width>20</ns1:Width>
          <ns1:Height>9</ns1:Height>
          <ns1:Units>IN</ns1:Units>
         </ns1:Dimensions>
        </ns1:RequestedPackageLineItems>
       </ns1:RequestedShipment>
      </ns1:RateRequest>
     </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>

我正在尝试获取 CountryCode、PostalCode Weight->Value 和所有维度等值,但命名空间让我感到困惑。每当我解析它并查看调试器时,我看到的任何给定变量都是 {SimpleXMLElement} [0] 但有些会显示输出 ->asXML() 但我访问数据的大多数尝试要么出错,要么返回 false ,或返回另一个 {SimpleXMLElement} [0]。我只想要这些节点的字符串/值!

以下示例,绝对没有输出:

    $fReq = simplexml_load_string($xmlRequest);
    $fReq->registerXPathNamespace('ns1', 'http://fedex.com/ws/rate/v9');
    $ns = $fReq->getNameSpaces(true);
    $rr = $fReq->children($ns['ns1']);
    echo $rr->asXML()."\n";

【问题讨论】:

标签: php xml simplexml


【解决方案1】:

我更喜欢使用 XMLReader:http://us3.php.net/manual/en/class.xmlreader.php

这是一个 PHP 示例表单,稍作修改以满足您的要求:

function xmlParse($content,$wrapperName,$callback,$limit=NULL){
    $xml = new XMLReader();
    $xml->xml($content);

    $n=0;
    $x=0;
    while($xml->read()){
        if($xml->nodeType==XMLReader::ELEMENT && $xml->name == $wrapperName){
            while($xml->read() && $xml->name != $wrapperName){
                if($xml->nodeType==XMLReader::ELEMENT){
                    $name = $xml->name;
                    $xml->read();
                    $value = $xml->value;
                    if(preg_match("/[^\s]/",$value)){
                        $subarray[$name] = $value;
                    }
                }
            }
            if($limit==NULL || $x<$limit){
                if($callback($subarray)){
                    $x++;
                }
                unset($subarray);
            }
            $n++;
        }
    }
    $xml->close();
}

xmlParse($test,'SOAP-ENV:Envelope','callback');

function callback($array){
    var_dump($array);

}

只需用你的 XML 执行这个,就会返回

Array
(
    [ns1:Key] => aaaaaaaaaaa
    [ns1:Password] => aaaaaaaaaaaaaaaaaaa
    [ns1:AccountNumber] => 11111111
    [ns1:MeterNumber] => 88888888
    [ns1:CustomerTransactionId] => 1
    [ns1:ServiceId] => crs
    [ns1:Major] => 9
    [ns1:Intermediate] => 0
    [ns1:Minor] => 0
    [ns1:ReturnTransitAndCommit] => true
    [ns1:ShipTimestamp] => 2013-08-06T12:39:26-04:00
    [ns1:DropoffType] => REGULAR_PICKUP
    [ns1:StreetLines] => 1234 Fifth Street
    [ns1:City] => Sixton
    [ns1:StateOrProvinceCode] => AR
    [ns1:PostalCode] => 72712
    [ns1:CountryCode] => US
    [ns1:RateRequestTypes] => ACCOUNT
    [ns1:PackageCount] => 1
    [ns1:PackageDetail] => INDIVIDUAL_PACKAGES
    [ns1:Units] => IN
    [ns1:Value] => 14
    [ns1:Length] => 20
    [ns1:Width] => 20
    [ns1:Height] => 9
)

问候

【讨论】:

  • 好吧,感谢您的回复,但我并不是真的想学习全新命令的全新语法。我用 xmlreader 尝试了一些东西,虽然它让我可以通过我给出的示例 xml 轻松获得一些属性,但我还必须解析从 fedex 返回的响应,其中包括一些重复元素,我真的不觉得就像试图找出另一个 xml 解析器来解决它们一样。问题是关于 SimpleXMLElement - 有人吗?
【解决方案2】:

除非您使用 XPath,否则您无需调用 registerXPathNamespace。但是,您确实需要遍历 SOAP Body 元素,这意味着您需要考虑两个命名空间,而不仅仅是一个。

不要依赖像ns1 这样的命名空间前缀在未来保持不变也是一个好主意;保证的部分是xmlns 属性中的实际URI。一种提高可读性的方法是为应用程序中使用的 XML 命名空间定义常量,并在必要时将它们传递给 -&gt;children()-&gt;attributes() 方法。

另请注意,-&gt;children()“选择”一个命名空间,直到另行通知,所以一旦您选择了 Fedex 命名空间并遍历到 RateRequest 节点,您就可以访问元素,就好像命名空间不是问题一样(因为本文档下面的所有内容都在同一个命名空间中)。

这是一个完整的示例,展示了它的外观 (see a live demo here)。

// Give your own aliases to namespaces, don't rely on the XML always having the same ones
define('NS_SOAP', 'http://schemas.xmlsoap.org/soap/envelope/');
define('NS_FEDEX_RATE', 'http://fedex.com/ws/rate/v9');

// Parse the XML
$sx = simplexml_load_string($xml_string);
// $sx now represents the <SOAP-ENV:Envelope> element

// Traverse through the SOAP Body
$sx_soap_body = $sx->children(NS_SOAP)->Body;

// Now "switch" to the Fedex namespace, and start with the RateRequest node
$sx_rate_request = $sx_soap_body->children(NS_FEDEX_RATE)->RateRequest;

// Now traverse as normal, e.g. to the Recipient's CountryCode
// (the string cast isn't necessary for echo, but is a good habit to get into)
echo (string)$sx_rate_request->RequestedShipment->Recipient->Address->CountryCode;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-21
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    相关资源
    最近更新 更多