skip to Main Content

There’s an xml file with multiple entries and i’m trying to sort it based on two children.
I’m trying to sort it first by a:DESIGN and then by a:COLOR.
i’ve made various attempts but it wont sort no matter what i tried.
Any help is highly appreciated.

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

Sample XML(a few entries only for demonstration. Uses real keys/values):

<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>

expected output(sorted by design and 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>

2

Answers


  1. You can use a powershell

    using assembly System
    using assembly System.Collections
    using assembly System.Xml.Linq
    
    $inputFilename = "c:temptest.xml"
    $outputFilename = "c:temptest1.xml"
    
    $doc = [System.Xml.Linq.XDocument]::Load($inputFilename)
    
    $GetItemsForXmlResult = $doc.Descendants().Where( {$_.Name.LocalName -eq "GetItemsForXmlResult"})
    $GetItemsForXmlResult = [System.Linq.Enumerable]::First($GetItemsForXmlResult)
    
    $nsA = $GetItemsForXmlResult.GetNamespaceOfPrefix("a")
    $sorteditems = $GetItemsForXmlResult.Elements($nsA + "ItemForXML")
    
    $sorteditems = [System.Linq.Enumerable]::ToList($sorteditems)
    Write-Host "type = " $sortedItems.GetType().ToString()
    
    $sorteditems = $sorteditems | Sort-Object -Property @{ Expression = { $_.Element($nsA + "DESIGN").Value}}, `
                                                      @{ Expression = { $_.Element($nsA + "COLOR").Value}}
    $sorteditems = $sorteditems.ForEach([System.Xml.Linq.XElement])
    $GetItemsForXmlResult.RemoveNodes()
    $GetItemsForXmlResult.Add($sorteditems)
    $doc.Save($outputFilename)
    
    Login or Signup to reply.
  2. It’s possible – but it’s pretty convoluted. I’m afraid I don’t have the time to fully annotate the code, but it basically involves creating a new skeleton document, searching the old document (using xpath) for your two keys, sorting them and then importing nodes from the old document, in that sorted order, into the new document. On top of that, you also have to handle namespaces…

    #first - on the old document
    $xpath->registerNamespace("a", "http://schemas.datacontract.org/2004/07/e_ShopConnector.Entities");
    $designs = $xpath->query('//a:DESIGN/text()');
    
    #create your skeleton new document
    $xmlstring = '<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">
        </GetItemsForXmlResult>
      </GetItemsForXmlResponse>';
      
    $newDoc = new DOMDocument();
    $newDoc->loadXML($xmlstring);
    $xpath2 = new DOMXPath($newDoc);
    $destination = $xpath2->query('//*[local-name()="GetItemsForXmlResult"]');
    
    #and the heavy lifting
    foreach($designs as $design) {
        $values[] = $design->nodeValue;
    }
    $u_des = array_unique(($values));
    sort($u_des);
    foreach ($u_des as $des){
        $targets = $xpath->query("//a:ItemForXML[.//a:DESIGN/text()= {$des}]");
        foreach ($targets as $target){
            $cols = $xpath->query('.//a:COLOR/text()',$target);
             $col_ar[] = $cols[0]->nodeValue;
              }
              sort($col_ar);
              foreach ($col_ar as $color){
                  $finals = $xpath->query("//a:ItemForXML[.//a:DESIGN/text()= {$des}][.//a:COLOR/text()= {$color}]");
                  foreach($finals as $final){
                        $node = $newDoc->importNode($final, true);
                        $destination[0]->appendChild($node);
                  }
          unset($col_ar);
        }
    }
    echo $newDoc->saveXML();
    

    Try this on your actual xml and see if it works. If not, it should work with some tinkering.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search