我正在记录API调用的错误请求/响应。为了将日志存储在数据库中,我想用*的替换信用卡号。
请求XML如下所示:
<xml>
<request servicekey="service key" branchcode="branch" language="EN" postalcode="Postal Code" country="CA" email="email@example.com">
<paxes>
<pax id="1" birthdate="19790215" firstname="John" lastname="Smith" />
<pax id="2" birthdate="19800828" firstname="Jane" lastname="Smith" />
</paxes>
<plans>
<plan code="Plan Code" >
<paxes>
<pax id="1" sumins="1200.00" />
<pax id="2" sumins="1480.31" />
</paxes>
</plan>
</plans>
<payments>
<payment amount="246.24" type="VI" ccnum="4111111111111111" ccexp="0711" ccname="John Smith" />
</payments>
</request>
</xml>
从这里我只需抓住付款节点和ccnum属性进行编辑(xml保存为$ requestXML):
$_req = new DOMDocument();
$_req->loadXML($requestXML);
$_xpathReq = new DOMXPath($_req);
$_reqDom = $_xpathReq->query("/xml/request/payments/payment");
$_reqDom->item(0)->setAttribute('ccnum','*****');
$requestXML = $_req->saveXML();
按预期工作,xml中的CC号替换为*'s
$ responseXML有点不同:
<string xmlns="http://tempuri.org/">
<xml>
<request servicekey="service key" branchcode="branch code" language="EN" postalcode="Postal Code" country="CA" email="email@example.com">
<paxes>
<pax id="1" birthdate="19790215" firstname="John" lastname="Smith" />
<pax id="2" birthdate="19800828" firstname="Jane" lastname="Smith" />
</paxes>
<plans>
<plan code="Plan Code">
<paxes>
<pax id="1" sumins="1200.00" />
<pax id="2" sumins="1480.31" />
</paxes>
</plan>
</plans>
<payments>
<payment amount="246.24" type="VI" ccnum="4111111111111111" ccexp="0711" ccname="John Smith" />
</payments>
</request>
<response>
<errors>
<error>Purchase Card Processing was not approved [-1]:Cancelled: null | CARD: **** | Exp: 1407 | Amount: $246.24</error>
</errors>
</response>
</xml>
</string>
和以前一样,我运行了一段非常相似的PHP代码:
$_req = new DOMDocument();
$_req->loadXML($responseXML);
$_xpathReq = new DOMXPath($_req);
$_reqDom = $_xpathReq->query("/string/xml/request/payments/payment");
$_reqDom->item(0)->setAttribute('ccnum','*****');
$responseXML = $_req->saveXML();
但是,当我执行此操作时,我会Fatal error: Call to a member function setAttribute() on a non-object
指向包含$_reqDom->item(0)->setAttribute('ccnum','*****');
2 xml之间的唯一区别是一个包含在字符串节点中,并且有一个额外的节点表示响应。我想我可以做一个解决方法(只需拔出响应节点并将其附加到请求xml),但我现在正处于这样一种工作方式,这是我的使命。
答案 0 :(得分:2)
问题是因为响应xml中的命名空间。您必须使用XPath选择器注册rootNamespace。以下代码将起作用:
$response = new DOMDocument();
$response->loadXML($responseXml);
$selector = new DOMXPath($response);
// get the root namespace
$rootNamespace = $response->lookupNamespaceUri(
$response->namespaceURI
);
// and register it with $selector. I'm using 'x' as the prefix
// you are free to use a different prefix
$selector->registerNamespace('x', $rootNamespace);
// You won't need to specify the whole path. You could just grab
// all payment node regardless of their location in the xml tree
$result = $selector->query('//x:payment');
foreach($result as $node) {
$node->setAttribute('ccnum', '*****');
}
$responseXml = $response->saveXML();
echo $responseXml;
答案 1 :(得分:1)
<string>
标记包含命名空间,您需要使用DOMXPath注册该命名空间。
$_req = new DOMDocument();
$_req->loadXML($responseXML);
$_xpathReq = new DOMXPath($_req);
$_xmlns = $_req->lookupNamespaceUri(NULL);
$_xpathReq->registerNamespace('x', $_xmlns);
$_reqDom = $_xpathReq->query("//x:xml/x:request/x:payments/x:payment");
$_reqDom->item(0)->setAttribute('ccnum','*****');
$responseXML = $_req->saveXML();
答案 2 :(得分:0)
我遇到了类似的问题,其中xml有几个名称空间定义如下:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
这使得无法进行DOMXPath
次查询。
通过以下方式导入xml来修复:
libxml_use_internal_errors(true);
$doc->loadHTML($rawXml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NSCLEAN);
libxml_use_internal_errors(false);
我希望这有助于某人。用这个把我的头发拉了下来......