PHP xpath在foreach循环中按属性获取元素

时间:2015-03-24 09:50:05

标签: php xml xpath attributes

我正在尝试遍历所有的LINE_ITEMS并且它工作正常但在foreach循环中我试图通过使用xpath访问单个LINE_ITEM属性,但我没有得到任何结果。有谁知道这个问题?

 foreach($items = $xmlData->xpath('//zw:LINE_ITEM') as $item) {
    $item->xpath('//namespace:PID[@type="erp_pid"]'); No result
}
$xmlData->xpath('//zw:LINE_ITEM') 

工作正常我得到所有LINE_ITEMS但是 当我尝试在项目上做一些xpath我没有得到任何结果。

如何访问例如“erp_pid”的PID值?

<?xml version="1.0" encoding="UTF-8"?>
<NM_DOCS>
    <NM_DOC>
        <DOCUMENT qualifier="default" role="original" test="false" type="orders">
            <VERSION>4.0</VERSION>
            <HEADER>
                <CONTROL_INFO>
                    <LAST_SAVE_DATE>2015-03-18T13:44:32+01:00</LAST_SAVE_DATE>
                    <PROCESS_TYPE>silent</PROCESS_TYPE>
                    <SOURCE>sales</SOURCE>

                </CONTROL_INFO>
                <SOURCING_INFO>
                    <REFERENCES>
                        <REFERENCE type="order_nexmart">
                            <ID>109546063</ID>
                            <DATES>
                                <DATE type="order">2015-03-18T13:44:30+01:00</DATE>
                            </DATES>
                        </REFERENCE>
                    </REFERENCES>
                </SOURCING_INFO>
                <DOCUMENT_INFO>
                    <DOCUMENT_ID>Test bestellnummer</DOCUMENT_ID>
                    <DATES>
                        <DATE type="delivery_ordered">2015-04-19T12:41:41+02:00</DATE>
                    </DATES>
                    <PARTIES>
                        <PARTY type="buyer">
                            <BUSINESS_ROLE>commercial</BUSINESS_ROLE>
                            <PORTAL_ID>BDE600028</PORTAL_ID>
                            <ADDITIONAL_IDS>                             
                            </ADDITIONAL_IDS>
                            <ADDRESS>                                
                            </ADDRESS>
                            <CONTACT_DETAILS>                                
                                <ACCOUNTS>
                                    <ID type="emart">sales.nexmart</ID>
                                </ACCOUNTS>
                            </CONTACT_DETAILS>
                        </PARTY>
                        <PARTY type="supplier">
                            <BUSINESS_ROLE>commercial</BUSINESS_ROLE>
                            <PORTAL_ID>zweygart_app_de</PORTAL_ID>
                            <ADDITIONAL_IDS>

                            </ADDITIONAL_IDS>
                            <ADDRESS>

                            </ADDRESS>
                            <CONTACT_DETAILS>

                            </CONTACT_DETAILS>
                        </PARTY>
                        <PARTY type="delivery">
                            <BUSINESS_ROLE>commercial</BUSINESS_ROLE>
                            <ADDRESS>

                            </ADDRESS>
                            <CONTACT_DETAILS>

                            </CONTACT_DETAILS>
                        </PARTY>
                        <PARTY type="invoice_recipient">
                            <ADDRESS>

                            </ADDRESS>
                            <CONTACT_DETAILS>

                            </CONTACT_DETAILS>
                        </PARTY>
                    </PARTIES>                    
                    <REMARKS>
                        <REMARK type="order">Test bemerkung</REMARK>
                    </REMARKS>
                </DOCUMENT_INFO>
            </HEADER>
            <LINE_ITEMS>
                <LINE_ITEM>                    
                    <PRODUCT_ID>
                        <SUPPLIER_PID>119556</SUPPLIER_PID>
                        <GTIN>4030646269130</GTIN>
                        <ADDITIONAL_PIDS>
                            <PID type="supplier_pid_original">119556</PID>
                            <PID type="gtin_original">4030646269130</PID>
                            <PID type="erp_pid">119556</PID>
                        </ADDITIONAL_PIDS>
                        <DESCRIPTIONS>
                            <DESCR type="short">short desc</DESCR>
                            <DESCR type="short_original">some text</DESCR>
                        </DESCRIPTIONS>
                    </PRODUCT_ID>                    
                </LINE_ITEM>
                <LINE_ITEM>                    
                    <PRODUCT_ID>
                        <SUPPLIER_PID>123456789</SUPPLIER_PID>
                        <GTIN>123456789</GTIN>
                        <ADDITIONAL_PIDS>
                            <PID type="supplier_pid_original">123456</PID>
                            <PID type="gtin_original">123456</PID>
                            <PID type="erp_pid">123456</PID>
                        </ADDITIONAL_PIDS>
                        <DESCRIPTIONS>
                            <DESCR type="short">short desc</DESCR>
                            <DESCR type="short_original">Some description</DESCR>
                        </DESCRIPTIONS>
                    </PRODUCT_ID>                                       

                </LINE_ITEM>
            </LINE_ITEMS>

        </DOCUMENT>
    </NM_DOC>
</NM_DOCS>

2 个答案:

答案 0 :(得分:3)

问题不是XPath而是SimpleXML。 SimpleXMLElement :: xpath()是有限的。它将结果转换为SimpleXMLElement对象的数组,但这里是DOM中的其他节点。更重要的是,您必须再次在每个新的SimpleXMLElement上注册名称空间。

$element = new SimpleXMLElement($xml);
$element->registerXPathNamespace('namespace', 'urn:foo');

foreach($element->xpath('//namespace:LINE_ITEMS/namespace:LINE_ITEM') as $item) {
  $item->registerXPathNamespace('namespace', 'urn:foo');
  var_dump((string)$item->xpath('.//namespace:PID[@type="erp_pid"]')[0]);
}

输出:

string(6) "119556"
string(6) "123456"

您可能会注意到我使用.为您的详细信息表达前缀。表达式开头的斜杠始终使其与文档本身相关,而不是当前节点。 .代表当前节点。

如果直接使用DOM,则创建一个单独的DOMXPath对象并在此对象上注册名称空间。此外,您可以使用返回标量值的XPath表达式。

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('namespace', 'urn:foo');
foreach($xpath->evaluate('//namespace:LINE_ITEMS/namespace:LINE_ITEM') as $node) {
  var_dump($xpath->evaluate('string(.//namespace:PID[@type="erp_pid"])', $node));
}

答案 1 :(得分:0)

这对我有用:

foreach($xmlData->LINE_ITEM as $item) {
    $erp = ( $item->xpath('//PID[@type="erp_pid"]'));
    foreach($erp as $v) {
        echo $v. " / ";
    }
}

只需删除xpath中的namespace,xml就不会使用命名空间。

如果要遍历xml的一部分,请确保使用正确的路径。