You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PHP按a:DESIGN和a:COLOR对XML文件排序?

问题描述

我有一个包含多条条目的XML文件,想要按两个子节点进行排序:先按a:DESIGN排序,再按a:COLOR排序。尝试多种方法后仍无法实现,求帮助。

我的代码

$xml = file_get_contents("http://79.129.20.64:8580/GlxConnector/GetItemsForXml");
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$list = iterator_to_array($xpath->evaluate('/*/*/*'));
uasort(
  $list,
  function($one, $two) use ($xpath) {
    return strcasecmp(
      $xpath->evaluate('string(a:DESIGN)', $one), 
      $xpath->evaluate('string(a:COLOR)', $two)
    );
  } 
);
$document->saveXML();
//var_dump($list);
$document->save('test1.xml');

示例XML(部分条目)

<GetItemsForXmlResponse xmlns="http://tempuri.org/">
    <GetItemsForXmlResult xmlns:a="http://schemas.datacontract.org/2004/07/e_ShopConnector.Entities" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:ItemForXML>
            <a:AVAILABILITY>false</a:AVAILABILITY>
            <a:CODE>127-0-368-32118-995</a:CODE>
            <a:COLOR>995</a:COLOR>
            <a:DESIGN>32118</a:DESIGN>
            <a:DIMENSION>160X230</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>121.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>BOHEME</a:SERIES>
        </a:ItemForXML>
        <a:ItemForXML>
            <a:AVAILABILITY>true</a:AVAILABILITY>
            <a:CODE>126-0-500-22570-795</a:CODE>
            <a:COLOR>795</a:COLOR>
            <a:DESIGN>22570</a:DESIGN>
            <a:DIMENSION>200X250</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>145.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>SYDNEY</a:SERIES>
        </a:ItemForXML>
        <a:ItemForXML>
            <a:AVAILABILITY>true</a:AVAILABILITY>
            <a:CODE>162-0-120-32118-995</a:CODE>
            <a:COLOR>995</a:COLOR>
            <a:DESIGN>32118</a:DESIGN>
            <a:DIMENSION>080X150</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>40.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>DELUXE</a:SERIES>
        </a:ItemForXML>
        <a:ItemForXML>
            <a:AVAILABILITY>true</a:AVAILABILITY>
            <a:CODE>136-0-252-75002-022</a:CODE>
            <a:COLOR>022</a:COLOR>
            <a:DESIGN>75002</a:DESIGN>
            <a:DIMENSION>140X180</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>76.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>PANAMA</a:SERIES>
        </a:ItemForXML>
        <a:ItemForXML>
            <a:AVAILABILITY>true</a:AVAILABILITY>
            <a:CODE>136-0-252-32118-995</a:CODE>
            <a:COLOR>995</a:COLOR>
            <a:DESIGN>32118</a:DESIGN>
            <a:DIMENSION>140X180</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>76.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>PANAMA</a:SERIES>
        </a:ItemForXML>
    </GetItemsForXmlResponse>
</GetItemsForXmlResult>

预期输出(按DESIGN和COLOR排序)

<GetItemsForXmlResponse xmlns="http://tempuri.org/">
    <GetItemsForXmlResult xmlns:a="http://schemas.datacontract.org/2004/07/e_ShopConnector.Entities" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:ItemForXML>
            <a:AVAILABILITY>true</a:AVAILABILITY>
            <a:CODE>162-0-120-32118-995</a:CODE>
            <a:COLOR>995</a:COLOR>
            <a:DESIGN>32118</a:DESIGN>
            <a:DIMENSION>080X150</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>40.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>DELUXE</a:SERIES>
        </a:ItemForXML>
        <a:ItemForXML>
            <a:AVAILABILITY>true</a:AVAILABILITY>
            <a:CODE>136-0-252-32118-995</a:CODE>
            <a:COLOR>995</a:COLOR>
            <a:DESIGN>32118</a:DESIGN>
            <a:DIMENSION>140X180</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>76.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>PANAMA</a:SERIES>
        </a:ItemForXML>
        <a:ItemForXML>
            <a:AVAILABILITY>false</a:AVAILABILITY>
            <a:CODE>127-0-368-32118-995</a:CODE>
            <a:COLOR>995</a:COLOR>
            <a:DESIGN>32118</a:DESIGN>
            <a:DIMENSION>160X230</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>121.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>BOHEME</a:SERIES>
        </a:ItemForXML>
        <a:ItemForXML>
            <a:AVAILABILITY>true</a:AVAILABILITY>
            <a:CODE>126-0-500-22570-795</a:CODE>
            <a:COLOR>795</a:COLOR>
            <a:DESIGN>22570</a:DESIGN>
            <a:DIMENSION>200X250</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>145.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>SYDNEY</a:SERIES>
        </a:ItemForXML>
        <a:ItemForXML>
            <a:AVAILABILITY>true</a:AVAILABILITY>
            <a:CODE>136-0-252-75002-022</a:CODE>
            <a:COLOR>022</a:COLOR>
            <a:DESIGN>75002</a:DESIGN>
            <a:DIMENSION>140X180</a:DIMENSION>
            <a:DISCOUNT_PERCENTAGE>0.000000000000</a:DISCOUNT_PERCENTAGE>
            <a:PRICE>76.000000000000</a:PRICE>
            <a:PRICE_AFTER_DISCOUNT>0.000000000000</a:PRICE_AFTER_DISCOUNT>
            <a:SERIES>PANAMA</a:SERIES>
        </a:ItemForXML>
    </GetItemsForXmlResponse>
</GetItemsForXmlResult>
解决方案

你的代码存在两个核心问题:

  1. 排序逻辑错误:当前代码把第一个节点的DESIGN和第二个节点的COLOR做比较,完全不符合先按DESIGN再按COLOR的排序规则。
  2. 排序后的节点未重新插入DOM:你只是对数组里的节点对象排序,但没有把这些排序后的节点重新放回文档中,所以保存的XML还是原顺序。

修正后的代码如下:

$xml = file_get_contents("http://79.129.20.64:8580/GlxConnector/GetItemsForXml");
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);

// 注册命名空间,确保XPath能正确识别a前缀
$xpath->registerNamespace('a', 'http://schemas.datacontract.org/2004/07/e_ShopConnector.Entities');

// 获取所有ItemForXML节点
$items = iterator_to_array($xpath->evaluate('//a:ItemForXML'));
// 获取父节点,后续要重新插入排序后的节点
$parent = $xpath->evaluate('//a:ItemForXML[1]/parent::*')[0];

// 正确的排序逻辑:先比较DESIGN,相同再比较COLOR
uasort($items, function($one, $two) use ($xpath) {
    $design1 = $xpath->evaluate('string(a:DESIGN)', $one);
    $design2 = $xpath->evaluate('string(a:DESIGN)', $two);
    // 先按DESIGN排序
    $designCompare = strcasecmp($design1, $design2);
    if ($designCompare !== 0) {
        return $designCompare;
    }
    // DESIGN相同则按COLOR排序
    $color1 = $xpath->evaluate('string(a:COLOR)', $one);
    $color2 = $xpath->evaluate('string(a:COLOR)', $two);
    return strcasecmp($color1, $color2);
});

// 先清空父节点下的所有ItemForXML节点
foreach ($items as $item) {
    $parent->removeChild($item);
}
// 再按排序后的顺序重新插入
foreach ($items as $item) {
    $parent->appendChild($item);
}

// 保存XML
$document->save('test1.xml');

关键说明

  • 命名空间注册:必须注册a前缀对应的命名空间,否则XPath无法正确定位到a:DESIGN和a:COLOR节点。
  • 排序逻辑修正:先对比两个节点的DESIGN值,只有当DESIGN相同时,才对比COLOR值,实现多级排序。
  • DOM节点重排:排序后的节点需要从父节点移除再重新插入,这样文档的节点顺序才会更新,保存后的XML才是排序后的结果。

内容的提问来源于stack exchange,提问作者Meni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 16:10:53