PHP XML DOM 文件在子节点内移动子子节点
PHP XML DOM Document move sub-sub-nodes within sub-node
我有一个 xml 这样的:
<?xml version="1.0" encoding="UTF-8"?>
<OrderListResponse>
<OrderListResponseContainer>
<DateFrom>2018-07-01T00:00:00+00:00</DateFrom>
<DateTo>2018-07-19T00:00:00+00:00</DateTo>
<Page>1</Page>
<TotalNumberOfPages>4</TotalNumberOfPages>
<Orders>
<Order>
<OrderID>158772</OrderID>
<Customer>
<Name><![CDATA[John Smith]]></Name>
<StreetAddress><![CDATA[33, Sunset Boulevrd]]></StreetAddress>
</Customer>
<Delivery>
<Name><![CDATA[John Smith]]></Name>
<StreetAddress><![CDATA[47, Rodeo Drive]]></StreetAddress>
</Delivery>
<Billing>
<Name><![CDATA[John Smith]]></Name>
<StreetAddress><![CDATA[33, Sunset Boulevrd]]></StreetAddress>
</Billing>
<Payment>
<Module>paypal</Module>
<TransactionID/>
</Payment>
<DatePurchased>2018-07-01 16:30:42</DatePurchased>
<DateLastModified>2018-07-02 21:08:28</DateLastModified>
<CheckoutMessage><![CDATA[]]></CheckoutMessage>
<Status>cancelled</Status>
<Currency>EUR</Currency>
<Products>
<Product>
<MxpID>44237</MxpID>
<SKU>IRF 8707TR</SKU>
<Quantity>3</Quantity>
<Price>2.46</Price>
</Product>
</Products>
<Total>
<SubTotal>7.38</SubTotal>
<Shipping>2.7</Shipping>
<Cod>0</Cod>
<Insurance>0</Insurance>
<Tax>1.62</Tax>
<Total>11.7</Total>
</Total>
</Order>
<Order>...</Order>
</Orders>
</OrderListResponseContainer>
</OrderListResponse>
虽然肯定有更好的方法,
为了解析所有订单,我构建了一个这样的例程:
$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->loadXML($response);
$xpath = new DOMXPath($xmlDoc);
$rootNode = $xpath->query('//OrderListResponseContainer/Orders')->item(0);
foreach($rootNode->childNodes as $node)
{
foreach($node->childNodes as $subnode)
{
Process User
foreach($subnode->childNodes as $subsubnode)
{
foreach($subsubnode->childNodes as $subsubsubnode)
{
Process Products and Sales
}
}
}
}
**** ADDED ****
I use the nested loops to create one xml for each product (each xml contains details about the buyer, the item and the
sale) and then this xml is passed to a Stored Procedure to generate
the user/item/sale records: For several reason I cannot bulky import
Users first, then Items and then Sales but while building the sale xml
I need some details from the Total Node and one way to get them is to
move Total Node on top of the XML, but clearly within the Order Node
**** ADDED ****
我需要在处理 Products 之前访问一些 Total 子节点
我找到的唯一解决方案是在开始时移动 Total 节点,但尽管尝试了很多次,但我一直未能成功:
这个想法是克隆 totalNode
和 appendbefore
OrderID
节点
问题是我需要处理子文档和 select 从节点本身克隆的节点,而我发现的所有示例都克隆了完整的 DocumentElement
也许使用 XSLT
可以实现更简单的解决方案?
可以提出解决方案吗?
我不完全理解你想说的关于克隆部分的内容。也许您可以编辑您的问题并阐明您的意思。
但是,关于访问 Total
节点...您也可以简单地使用 XPath。
$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->loadXML($response);
$xpath = new DOMXPath($xmlDoc);
// first, let's fetch all <Order> elements
$orders = $xpath->query('//OrderListResponseContainer/Orders/Order');
// loop through all <Order> elements
foreach( $orders as $order ) {
/*
There's all sorts of ways you could convert <Total> to something useful
*/
// Example 1.
// fetch <Total> that is a direct child (./) of our context node (second argument) $order
$total = $xpath->query( './Total', $order )->item( 0 );
// then do something like
$subTotal = $total->getElementsByTagName( 'SubTotal' )->item( 0 );
$shipping = $total->getElementsByTagName( 'Shipping' )->item( 0 );
// ... etc. for each child node of <Total>
// or perhaps simply convert it to a SimpleXMLElement
$total = simplexml_import_dom( $total );
var_dump( $total );
// and then access the values like this:
$total->SubTotal;
$total->Shipping;
// ... etc.
// Example 2.1
// fetch all children of <Total> into an array
$total = [];
foreach( $xpath->query( './Total/*', $order ) as $totalNode ) {
$total[ $totalNode->nodeName ] = $totalNode->textContent;
}
var_dump( $total );
// Example 2.2
// fetch all children of <Total> into a stdClass object
$total = new \stdClass;
foreach( $xpath->query( './Total/*', $order ) as $totalNode ) {
$total->{ $totalNode->nodeName } = $totalNode->textContent;
}
var_dump( $total );
/*
Now, after this you can create and process the Customer and Products data
in a similar fashion as I've shown how to process the Total data above
*/
}
我有一个 xml 这样的:
<?xml version="1.0" encoding="UTF-8"?>
<OrderListResponse>
<OrderListResponseContainer>
<DateFrom>2018-07-01T00:00:00+00:00</DateFrom>
<DateTo>2018-07-19T00:00:00+00:00</DateTo>
<Page>1</Page>
<TotalNumberOfPages>4</TotalNumberOfPages>
<Orders>
<Order>
<OrderID>158772</OrderID>
<Customer>
<Name><![CDATA[John Smith]]></Name>
<StreetAddress><![CDATA[33, Sunset Boulevrd]]></StreetAddress>
</Customer>
<Delivery>
<Name><![CDATA[John Smith]]></Name>
<StreetAddress><![CDATA[47, Rodeo Drive]]></StreetAddress>
</Delivery>
<Billing>
<Name><![CDATA[John Smith]]></Name>
<StreetAddress><![CDATA[33, Sunset Boulevrd]]></StreetAddress>
</Billing>
<Payment>
<Module>paypal</Module>
<TransactionID/>
</Payment>
<DatePurchased>2018-07-01 16:30:42</DatePurchased>
<DateLastModified>2018-07-02 21:08:28</DateLastModified>
<CheckoutMessage><![CDATA[]]></CheckoutMessage>
<Status>cancelled</Status>
<Currency>EUR</Currency>
<Products>
<Product>
<MxpID>44237</MxpID>
<SKU>IRF 8707TR</SKU>
<Quantity>3</Quantity>
<Price>2.46</Price>
</Product>
</Products>
<Total>
<SubTotal>7.38</SubTotal>
<Shipping>2.7</Shipping>
<Cod>0</Cod>
<Insurance>0</Insurance>
<Tax>1.62</Tax>
<Total>11.7</Total>
</Total>
</Order>
<Order>...</Order>
</Orders>
</OrderListResponseContainer>
</OrderListResponse>
虽然肯定有更好的方法, 为了解析所有订单,我构建了一个这样的例程:
$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->loadXML($response);
$xpath = new DOMXPath($xmlDoc);
$rootNode = $xpath->query('//OrderListResponseContainer/Orders')->item(0);
foreach($rootNode->childNodes as $node)
{
foreach($node->childNodes as $subnode)
{
Process User
foreach($subnode->childNodes as $subsubnode)
{
foreach($subsubnode->childNodes as $subsubsubnode)
{
Process Products and Sales
}
}
}
}
**** ADDED ****
I use the nested loops to create one xml for each product (each xml contains details about the buyer, the item and the sale) and then this xml is passed to a Stored Procedure to generate the user/item/sale records: For several reason I cannot bulky import Users first, then Items and then Sales but while building the sale xml I need some details from the Total Node and one way to get them is to move Total Node on top of the XML, but clearly within the Order Node
**** ADDED ****
我需要在处理 Products 之前访问一些 Total 子节点
我找到的唯一解决方案是在开始时移动 Total 节点,但尽管尝试了很多次,但我一直未能成功:
这个想法是克隆 totalNode
和 appendbefore
OrderID
节点
问题是我需要处理子文档和 select 从节点本身克隆的节点,而我发现的所有示例都克隆了完整的 DocumentElement
也许使用 XSLT
可以实现更简单的解决方案?
可以提出解决方案吗?
我不完全理解你想说的关于克隆部分的内容。也许您可以编辑您的问题并阐明您的意思。
但是,关于访问 Total
节点...您也可以简单地使用 XPath。
$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->loadXML($response);
$xpath = new DOMXPath($xmlDoc);
// first, let's fetch all <Order> elements
$orders = $xpath->query('//OrderListResponseContainer/Orders/Order');
// loop through all <Order> elements
foreach( $orders as $order ) {
/*
There's all sorts of ways you could convert <Total> to something useful
*/
// Example 1.
// fetch <Total> that is a direct child (./) of our context node (second argument) $order
$total = $xpath->query( './Total', $order )->item( 0 );
// then do something like
$subTotal = $total->getElementsByTagName( 'SubTotal' )->item( 0 );
$shipping = $total->getElementsByTagName( 'Shipping' )->item( 0 );
// ... etc. for each child node of <Total>
// or perhaps simply convert it to a SimpleXMLElement
$total = simplexml_import_dom( $total );
var_dump( $total );
// and then access the values like this:
$total->SubTotal;
$total->Shipping;
// ... etc.
// Example 2.1
// fetch all children of <Total> into an array
$total = [];
foreach( $xpath->query( './Total/*', $order ) as $totalNode ) {
$total[ $totalNode->nodeName ] = $totalNode->textContent;
}
var_dump( $total );
// Example 2.2
// fetch all children of <Total> into a stdClass object
$total = new \stdClass;
foreach( $xpath->query( './Total/*', $order ) as $totalNode ) {
$total->{ $totalNode->nodeName } = $totalNode->textContent;
}
var_dump( $total );
/*
Now, after this you can create and process the Customer and Products data
in a similar fashion as I've shown how to process the Total data above
*/
}