Commit 85ac579
authored
Fix document order in REXML::XPathParser.sort (#356)
`REXML::XPathParser.sort` keys each node on its index under each
ancestor, but two different nodes could end up with the same key, and
ties are then broken arbitrarily by an unstable sort.
The walk stopped at the root element, so the root and everything outside
it -- comments and PIs at document level -- all keyed on an empty array:
```
<!--c1--><?pi1?><root/><!--c2--><?pi2?>
```
//comment() | //processing-instruction()
was: c1, c2, pi1, pi2 want: c1, pi1, c2, pi2
Walk up to the document instead, so those nodes are ordered against each
other.
An attribute borrowed the key of the element carrying it, so the element
and its attributes tied:
```
<root><a x="1" y="2"><b/></a></root>
```
//a/@* | //a | //a/*
was: @x, @y, <a>, <b> want: <a>, @x, @y, <b>
Extend an attribute's key past its element's with ATTRIBUTE_POSITION. A
child index is never negative, so -1 lands the attributes after `<a>`
and ahead of `<b>`, which is where document order wants them.
The attributes of one element tied with each other too, which went
unnoticed because a small enough sort leaves its input alone:
<a z="1" m="2" b="3"/> //a/@* -> z, m, b
<a z="1" ... 26 attributes/> //a/@* -> scrambled
XPath 1.0 leaves their relative order implementation dependent, but
document order is a total ordering, so it has to be decided. Key them on
where they were written, which is the order the small case already
appeared to have. Finding that out means walking the attribute list, so
index the whole list at once and remember it for the rest of the sort;
asking per attribute would make sorting quadratic in the number of
attributes an element carries, which is something a document gets to
choose.
The ancestor walk becomes a method of its own, since both branches of
the key need it. It, attribute_position and ATTRIBUTE_POSITION are
private rather than public names marked :nodoc:, sort being the only
part callers outside the class use.1 parent 9694327 commit 85ac579
2 files changed
Lines changed: 143 additions & 13 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
804 | 804 | | |
805 | 805 | | |
806 | 806 | | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
807 | 812 | | |
808 | 813 | | |
809 | 814 | | |
| |||
815 | 820 | | |
816 | 821 | | |
817 | 822 | | |
818 | | - | |
819 | | - | |
820 | | - | |
821 | | - | |
822 | | - | |
823 | | - | |
824 | | - | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
825 | 832 | | |
826 | | - | |
827 | | - | |
828 | | - | |
829 | | - | |
830 | 833 | | |
831 | | - | |
832 | | - | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
833 | 865 | | |
| 866 | + | |
834 | 867 | | |
| 868 | + | |
835 | 869 | | |
836 | 870 | | |
837 | 871 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
3 | 5 | | |
4 | 6 | | |
5 | 7 | | |
| 8 | + | |
6 | 9 | | |
7 | 10 | | |
8 | 11 | | |
| |||
1564 | 1567 | | |
1565 | 1568 | | |
1566 | 1569 | | |
| 1570 | + | |
| 1571 | + | |
| 1572 | + | |
| 1573 | + | |
| 1574 | + | |
| 1575 | + | |
| 1576 | + | |
| 1577 | + | |
| 1578 | + | |
| 1579 | + | |
| 1580 | + | |
| 1581 | + | |
| 1582 | + | |
| 1583 | + | |
| 1584 | + | |
| 1585 | + | |
| 1586 | + | |
| 1587 | + | |
| 1588 | + | |
| 1589 | + | |
| 1590 | + | |
| 1591 | + | |
| 1592 | + | |
| 1593 | + | |
| 1594 | + | |
| 1595 | + | |
| 1596 | + | |
| 1597 | + | |
| 1598 | + | |
| 1599 | + | |
| 1600 | + | |
| 1601 | + | |
| 1602 | + | |
| 1603 | + | |
| 1604 | + | |
| 1605 | + | |
| 1606 | + | |
| 1607 | + | |
| 1608 | + | |
| 1609 | + | |
| 1610 | + | |
| 1611 | + | |
| 1612 | + | |
| 1613 | + | |
| 1614 | + | |
| 1615 | + | |
| 1616 | + | |
| 1617 | + | |
| 1618 | + | |
| 1619 | + | |
| 1620 | + | |
| 1621 | + | |
| 1622 | + | |
| 1623 | + | |
| 1624 | + | |
| 1625 | + | |
| 1626 | + | |
| 1627 | + | |
| 1628 | + | |
| 1629 | + | |
| 1630 | + | |
| 1631 | + | |
| 1632 | + | |
| 1633 | + | |
| 1634 | + | |
| 1635 | + | |
| 1636 | + | |
| 1637 | + | |
| 1638 | + | |
| 1639 | + | |
| 1640 | + | |
| 1641 | + | |
| 1642 | + | |
| 1643 | + | |
| 1644 | + | |
| 1645 | + | |
| 1646 | + | |
1567 | 1647 | | |
1568 | 1648 | | |
1569 | 1649 | | |
| |||
1607 | 1687 | | |
1608 | 1688 | | |
1609 | 1689 | | |
| 1690 | + | |
| 1691 | + | |
| 1692 | + | |
| 1693 | + | |
| 1694 | + | |
| 1695 | + | |
| 1696 | + | |
| 1697 | + | |
| 1698 | + | |
| 1699 | + | |
| 1700 | + | |
| 1701 | + | |
| 1702 | + | |
| 1703 | + | |
| 1704 | + | |
| 1705 | + | |
1610 | 1706 | | |
1611 | 1707 | | |
0 commit comments