Here's what I'd do, and it's certainly not the cleanest way, but it should work.
This assumes you're working with your own pages, and not the scenario where you're getting the page html via http request to some external site (e.g. via CURL) and needing to parse it. DOMDocument serves just fine for the latter case. This solution is for the former, as I'm assuming that since you're working with javascript on the client-side of it, it's probably your own page (unless you're injecting that javascript into the page after it's loaded).
First of all, inside each list item, I'd include a server-side accessible input tag. It will serve to keep track of the position and value, and pass it to the server-side script on form submission.
<form method="POST">
<ul id="sortable">
<li class="ui-state-default">1
<input id="the_list_item_1" name="the_list_item[]" type="text" value="1_0" style="display: none;">
</li>
...
</ul>
</form>
The value is the item's actual value (the example had them ranged 1 - 12) and it's position separated by an underscore (value + "_" + position);
The list needs to be inside a form variable if you only need to submit the list to the server for processing when the user's done. However, if you intend to only use Ajax to get that data to the server, this solution isn't really necessary (as you'd simply just use jquery to get each position and value pair and send them directly in your ajax call).
You'll need to handle updating these input tags as the user drags items and changes the ordering of the list. See here if you need to know how to work with the sortable events. Perhaps, on update, for each list item call this function with the new position:
function update_pos(value,pos)
{
$("#the_list_item_"+value).val(value+"_"+pos);
}
So on form submit, we're now on the PHP side.
$list_items = $_POST["the_list_item"]; // This is basically an array of all the list_items, thanks to naming all the list items with "the_list_item[]", note the empty subscript (square braces).
$ordered_list_items = array(); // Let's push them into an associative array.
foreach($list_items as $li)
{
$li_split = explode("_",$li);
if(count($li_split) <= 0)
continue; // maybe you'd want to handle this situation differently, it really shouldn't happen at all though. Here, I'm just ignoring nonsensical values.
$item_id = $li_split[0];
$pos = $li_split[1];
$ordered_list_items[$item_id] = $pos;
}
// Then later you can shoot through this list and do whatever with them.
foreach($ordered_list_items as $item_id => $pos)
{
// postgres perhaps. Insert if not already there, update regardless.
pg_query("insert into the_list_item (item_id,position) select '$item_id','$pos' where '$item_id' not in (select item_id from the_list_item where '$item_id' = item_id limit 1));
pg_query("update the_list_item set position = '$pos' where item_id = '$item_id'");
}
Of course, all that said, depending on your needs you may need to be reloading this data onto the page. So looping through your db results (perhaps, for that user), you'd output each list_item into place.
$list_items = pg_fetch_all(pg_query($sql)); // $sql needs to be the query to get the results. Probably should order by position ascending.
$lic = count($list_items);
?>
<html> and stuff
<form method="POST">
<ul id="sortable">
<?php
for($i = 0; $i < $lic; $i++)
{
$li = $list_items[$i];
echo "<li class=\"ui-state-default\">".$li["item_id"]."<input id=\"the_list_item_".$li["item_id"]."\" name=\"the_list_item[]\" type=\"text\" value=\"".$li["item_id"]."_".$li["position"]."\" style=\"display: none;\"></li>";
}
?>
</ul>
</form>