简体   繁体   中英

How can I get my XML Link List automatically sorted?

I have a well working livesearch which takes the results from my XML List. But I need to add many links to it and I wonder if there is a way to automatically sort them alphabetically to save time. I need them sorted from A to Z because the results should not be in a random order.

Is there a way to maybe add them into a php page or something and display them sorted in my XML file? Or maybe work with classes?

<pages>
<link>
<title>Volvo</title>
<url>https://www.example.com</url>
</link>
<link>
<title>Audi</title>
<url>https://www.example.com</url>
</link>
<link>
<title>Mercedes</title>
<url>https://www.example.com</url>
</link>
</pages>

This is the PHP Code:

<?php
$xmlDoc=new DOMDocument();
$xmlDoc->load("links.xml");

$x=$xmlDoc->getElementsByTagName('link');

//get the q parameter from URL
$q=$_GET["q"];

//lookup all links from the xml file if length of q>0
if (strlen($q)>0) {
  $hint="";
  for($i=0; $i<($x->length); $i++) {
    $y=$x->item($i)->getElementsByTagName('title');
    $z=$x->item($i)->getElementsByTagName('url');
    if ($y->item(0)->nodeType==1) {
      //find a link matching the search text
      if (strpos(strtolower($y->item(0)->childNodes->item(0)->nodeValue), strtolower($q)) === 0) {
        if ($hint=="") {
          $hint="<a href='" .
          $z->item(0)->childNodes->item(0)->nodeValue .
          "' target='_blank'>" .
          $y->item(0)->childNodes->item(0)->nodeValue . "</a>";
        } else {
          $hint=$hint . "<br /><a href='" .
          $z->item(0)->childNodes->item(0)->nodeValue .
          "' target='_blank'>" .
          $y->item(0)->childNodes->item(0)->nodeValue . "</a>";
        }
      }
    }
  }
}

// Set output to "no suggestion" if no hint was found
// or to the correct values
if ($hint=="") {
  $response="no suggestion";
} else {
  $response=$hint;
}

//output the response
echo $response;
?>

The DOM methods return node lists, more specific a \\DOMNodeList object. This object implements the Traversable interface (The parent interface for Iterators). You can use iterator_to_array() to convert the node list into an array and usort() to sort that array.

To filter the link nodes directly you can use an Xpath expression that calls back into PHP.

// bootstrap the link xml
$source = new DOMDocument();
$source->loadXml(getXML());
$xpath = new DOMXpath($source);

// use ext/intl transliterator to create a lowercase ascii string
function normalize(string $string) {
    return \Transliterator::create('Any-Lower; Latin-ASCII')->transliterate($string);
}

// register the "normalize" function 
$xpath->registerNamespace("php", "http://php.net/xpath");
$xpath->registerPhpFunctions(['normalize']);

// build an expression that filters the nodes using a search string
$searchFor = 'd';
$expression = '//link[
    contains(php:function("normalize", string(title)), "'.$searchFor.'")
]';
// map data into a nested array
$links = array_map(
    function(\DOMNode $node) use ($xpath) {
        return [ 
            'title' => $xpath->evaluate('string(title)', $node),
            'url' => $xpath->evaluate('string(url)', $node)
        ];
    },
    iterator_to_array($xpath->evaluate($expression))
);

// create a locale specific string collator
$collator = new Collator('en_US');
// sort the link data array
usort(
    $links,    
    function(array $a, array $b) use ($collator) {
        return $collator->compare($a['title'], $b['title']);
    }
);

var_dump($links);

Output:

array(2) {
  [0]=>
  array(2) {
    ["title"]=>
    string(4) "Audi"
    ["url"]=>
    string(23) "https://www.example.com"
  }
  [1]=>
  array(2) {
    ["title"]=>
    string(8) "Mercedes"
    ["url"]=>
    string(23) "https://www.example.com"
  }
}

DOM can be used to create the HTML output also. This allows the DOM serializer to take care of special characters.

// a target document for the HTML output
$target = new DOMDocument();
// fragments are node lists that can be treated as a single node
$targetFragment = $target->createDocumentFragment();

foreach($links as $link) {
    // if the fragment contains nodes add a break
    if ($targetFragment->hasChildNodes()) {
        $targetFragment->appendChild($target->createElement('br'));
    }
    
    // create and append "a" element node
    $targetFragment->appendChild(
        $a = $target->createElement('a')
    );
    $a->setAttribute('target', '_blank');
    $a->setAttribute('href', $link['url']);
    $a->textContent = $link['title'];
}
// save the fragment as HTML
echo $target->saveHTML($targetFragment); 

Output:

<a target="_blank" href="https://www.example.com">Audi</a><br><a target="_blank" href="https://www.example.com">Mercedes</a>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM