【问题标题】:PHP: How can I easily combine or merge simpleXML elements using a node value?PHP:如何使用节点值轻松组合或合并 simpleXML 元素?
【发布时间】:2012-02-03 05:03:22
【问题描述】:

我是 stackoverflow 的新手,所以请提前原谅我。 :)

我正在尝试合并具有相同 BranchCode 的对象,基本上,只是将 Branch 作为主 Product 节点的子节点。请在下面查看我的示例 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>

【问题讨论】:

  • 该 XML 文档中还有其他内容吗?如果没有,最简单的方法是通过迭代每个产品并复制其数据来以正确的格式创建新文档。否则,如果您必须修改现有文档的结构,使用 DOM(甚至可能是 XSLT)比使用 SimpleXML 更简单。
  • @JoshDavis:是的,XML 中的其他数据看起来像具有不同 ProductCode 的数据。请查看更新后的帖子。感谢您花时间查看我的问题。干杯!

标签: php arrays multidimensional-array merge simplexml


【解决方案1】:

没有任何内置函数可以合并文档,因此您必须“手动”完成。一种方法是在 PHP 中使用DOM。选择要通过 XPath 处理的 &lt;Product&gt; 节点,创建一个 &lt;Branch&gt; 节点,将所有子节点移动到该节点,然后将 &lt;Branch&gt; 节点附加到正确的 &lt;Product&gt;

$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();

【讨论】:

    【解决方案2】:

    或者,您可以使用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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-18
      • 2010-10-07
      • 2019-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 1970-01-01
      相关资源
      最近更新 更多