2012-02-03 101 views
0

我有點新在這裏在stackoverflow所以提前原諒我。 :)PHP:如何使用節點值輕鬆地組合或合併simpleXML元素?

我想合併對象與相同的BranchCode和基本上,只是使分支作爲主要產品節點的孩子。請參閱下面的示例XML。謝謝。

我有這樣的XML(simpleXMLElement->asXML()):

<?xml version="1.0" encoding="utf-8"?> 
<ArrayOfProduct xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>14</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>150</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>226</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>227</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>26</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>34</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>35</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>400A</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>405A</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>460A</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>57</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>83</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>C3</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-02-2166</ProductCode> 
    <BranchCode>Global</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>14</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>150</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>226</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>227</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>26</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>34</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>35</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>400A</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>405A</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>460A</BranchCode> 
    <Available>5.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>57</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>83</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>C3</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>0.00</AvailableGlobally> 
    </Product> 
    <Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-051-2030</ProductCode> 
    <BranchCode>Global</BranchCode> 
    <Available>0.00</Available> 
    <AvailableCSL>0.00</AvailableCSL> 
    <AvailableGlobally>5.00</AvailableGlobally> 
    </Product> 
</ArrayOfProduct> 

而且我要的輸出類似於此:

<?xml version="1.0" encoding="utf-8"?> 
<ArrayOfProduct xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
<Product> 
    <Customer>238500</Customer> 
    <ProductCode>AAA-50-3535</ProductCode> 
    <Branch> 
     <BranchCode>C3</BranchCode> 
     <Available>10.00</Available> 
     <AvailableCSL>0.00</AvailableCSL> 
     <AvailableGlobally>100.00</AvailableGlobally> 
    </Branch> 
    <Branch> 
     <BranchCode>A5</BranchCode> 
     <Available>20.00</Available> 
     <AvailableCSL>0.00</AvailableCSL> 
     <AvailableGlobally>100.00</AvailableGlobally> 
    </Branch> 
    .... 
    .... 
    </Product> 
    .... 
    .... 
</ArrayOfProduct> 
+0

還有什麼在那個XML文件中?如果沒有,最簡單的方法是通過迭代每個產品並複製其數據來以正確的格式創建新文檔。否則,如果您必須修改現有文檔的結構,那麼使用DOM(甚至可能是XSLT)而不是SimpleXML會更簡單。 – 2012-02-03 05:29:47

+0

@JoshDavis:是的,XML中的其他數據看起來像使用不同的ProductCode。請參閱更新後的帖子。感謝您花時間看我的問題。乾杯! – 2012-02-03 13:10:48

+0

[SimpleXML:追加一棵樹到另一個]的可能重複(http://stackoverflow.com/questions/3418019/simplexml-append-one-tree-to-another) – Line 2014-02-28 15:31:49

回答

0

沒有將合併文檔任何內置功能,所以你必須「親手做」。一種方法是使用PHP,使用DOM。選擇要通過XPath處理的<Product>節點,創建一個將移動所有子節點的節點<Branch>,然後將<Branch>節點附加到正確的<Product>

$dom = new DOMDocument; 
// Those two options are purely for cosmetic reasons, you can remove them 
$dom->formatOutput = true; 
$dom->preserveWhiteSpace = false; 
$dom->load('old.xml'); 

$ProductNodes = array(); 

$DOMXPath = new DOMXPath($dom); 

foreach ($DOMXPath->query('/ArrayOfProduct/Product') as $Product) 
{ 
    // Create a new <Branch/> 
    $Branch = $dom->createElement('Branch'); 

    // Move the nodes to the <Branch/>, except for <Customer/> and <ProductCode/> 
    $childNodes = $DOMXPath->query('./*[name() != "Customer"][name() != "ProductCode"]', $Product); 
    foreach ($childNodes as $child) 
    { 
     $Branch->appendChild($Product->removeChild($child)); 
    } 

    $key = $Product->getElementsByTagName('Customer')->item(0)->textContent 
     . ':' 
     . $Product->getElementsByTagName('ProductCode')->item(0)->textContent; 

    // If it's not the first product with that combination of Customer:ProductCode, we remove the 
    // node, otherwise we keep it and we'll append other branches to it 
    if (isset($ProductNodes[$key])) 
    { 
     $Product->parentNode->removeChild($Product); 
    } 
    else 
    { 
     $ProductNodes[$key] = $Product; 
    } 

    $ProductNodes[$key]->appendChild($Branch); 
} 

echo $dom->saveXML(); 
0

或者,您可以使用Identity Transform更改文檔的結構。這裏有一個這樣的例子:(這個不處理PI和註釋節點)

copy.xsl

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="xml" encoding="utf-8" indent="yes" /> 

    <xsl:template match="@* | *"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | *"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="/ArrayOfProduct/Product"> 
     <!-- Check if it's the first Product node with that combination of Customer and ProductCode --> 
     <xsl:if test="not(preceding-sibling::Product[Customer = current()/Customer and ProductCode = current()/ProductCode])"> 
      <xsl:copy> 
       <!-- Copy the Customer and ProductCode nodes first --> 
       <xsl:copy-of select="Customer | ProductCode" /> 

       <!-- Create a Branch for every Product with that combination of Customer and ProductCode --> 
       <xsl:for-each select="/ArrayOfProduct/Product[Customer = current()/Customer and ProductCode = current()/ProductCode]"> 
        <Branch> 
         <!-- Copy their children, except for Customer and ProductCode --> 
         <xsl:copy-of select="*[name() != 'Customer'][name() != 'ProductCode']"/> 
        </Branch> 
       </xsl:for-each> 
      </xsl:copy> 
     </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

可以在PHP中運行它:

$xml = new DOMDocument; 
$xml->load('old.xml'); 

$xsl = new DOMDocument; 
$xsl->load('copy.xsl'); 

$xslt = new XSLTProcessor; 
$xslt->importStylesheet($xsl); 

echo $xslt->transformToXml($xml);