1

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>
3
  • Please edit your question and add the exact expected output from the sample xml. Commented Oct 13, 2022 at 13:38
  • @Jack Fleeting Thank you. i have added the expected output. Commented Oct 14, 2022 at 6:55
  • Unsure why you think the usort will alter the $document? You are sorting an array called $list, not $document. I'm guessing you will need to rebuild the XML document based on $list before saving Commented Oct 14, 2022 at 6:57

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

You can use a powershell

using assembly System
using assembly System.Collections
using assembly System.Xml.Linq

$inputFilename = "c:\temp\test.xml"
$outputFilename = "c:\temp\test1.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)

2 Comments

Thank you very much for your solution. I would like for the sorting to be done real time using php.
You can always call the power shell from other languages. Don't no other ways of doing it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.