Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Changeset 3279

Show
Ignore:
Timestamp:
02/24/08 17:42:36 (9 months ago)
Author:
kris
Message:

moved XPath support into Document instead, since it makes the API cleaner.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/example/text/xmlpath.d

    r3255 r3279  
    1111import tango.time.StopWatch; 
    1212import tango.text.xml.Document; 
    13 import tango.text.xml.XmlPath; 
    1413import tango.text.xml.XmlPrinter; 
    1514 
     
    4140        // time some queries 
    4241        StopWatch w; 
    43         auto query = new XmlPath!(char)
    44         auto set = query(doc)
     42        uint count = 100000
     43        auto set = doc.query
    4544 
    4645        // simple lookup: locate a specific named element 
    4746        w.start; 
    48         uint count= 1000000; 
    4947        for (uint i = count; --i;) 
    50              set = query(doc).child("element").child("sub").child("second")
     48             set = doc.query["element"]["sub"]["child"]
    5149        result ("generic lookups/s", count/w.stop, set); 
    5250 
     
    5452        w.start; 
    5553        for (uint i = count; --i;) 
    56              set = query(doc).child("element").child("sub").attribute; 
     54             set = doc.query.child("element").child("sub").attribute; 
    5755        result ("attribute lookups/s", count/w.stop, set); 
    5856 
     
    6058        w.start; 
    6159        for (uint i = count; --i;) 
    62              set = query(doc).descendent.filter((query.Node n) {return n.hasText("value");}); 
     60             set = doc.query.descendant.filter((doc.Node n) {return n.hasText("value");}); 
    6361        result ("text-predicate lookups/s", count/w.stop, set); 
    6462 
     
    6664        w.start; 
    6765        for (uint i = count; --i;) 
    68              set = query(doc).descendent.filter((query.Node n) {return n.hasAttribute("attrib1");}); 
     66             set = doc.query.descendant.filter((doc.Node n) {return n.hasAttribute("attrib1");}); 
    6967        result ("attr-predicate lookups/s", count/w.stop, set); 
     68 
     69        // filtered lookup: locate all elements with more than 1 child 
     70        w.start; 
     71        for (uint i = count; --i;) 
     72             set = doc.query.descendant.filter((doc.Node n) {return n.query[].count > 1;}); 
     73        result ("text-predicate lookups/s", count/w.stop, set); 
    7074 
    7175} 
  • trunk/tango/text/xml/Document.d

    r3274 r3279  
    8181                                freelists; 
    8282        private uint[T[]]       namespaceURIs; 
     83 
     84        private XmlPath!(T)     xpath; 
    8385         
    8486        static const T[] xmlns = "xmlns"; 
     
    104106                root = allocate; 
    105107                root.type = XmlNodeType.Document; 
     108 
     109                xpath = new XmlPath!(T); 
     110        } 
     111 
     112        /*********************************************************************** 
     113         
     114                Return an xpath handle to query this document. This starts 
     115                at the document root. 
     116 
     117                See also Node.query 
     118 
     119        ***********************************************************************/ 
     120         
     121        final XmlPath!(T).NodeSet query () 
     122        { 
     123                return xpath.start (root); 
    106124        } 
    107125 
     
    113131        ***********************************************************************/ 
    114132         
    115         final Document collect () 
     133        private final Document collect () 
    116134        { 
    117135                root.lastChild_ =  
     
    242260 
    243261                auto p = &list[index++]; 
    244                 p.document_ = this; 
     262                p.document = this; 
    245263                p.parent_ = 
    246264                p.prevSibling_ =  
     
    315333                public T[]              localName; 
    316334                public T[]              rawValue; 
     335                public Document         document; 
    317336                 
    318337                package Node            parent_, 
     
    323342                                        firstAttr_, 
    324343                                        lastAttr_; 
    325                 package Document        document_; 
    326  
    327                 /*************************************************************** 
    328                  
    329                         Return the document 
    330  
    331                 ***************************************************************/ 
    332          
    333                 Document document () {return document_;} 
    334          
     344 
    335345                /*************************************************************** 
    336346                 
     
    433443                Node root () 
    434444                { 
    435                         return document_.root; 
     445                        return document.root; 
    436446                } 
    437447 
     
    563573                        assert (tree); 
    564574                        tree = tree.clone; 
    565                         tree.migrate (document_); 
     575                        tree.migrate (document); 
    566576                        append (tree); 
    567577                        return tree; 
     
    580590                { 
    581591                        tree.detach; 
    582                         if (tree.document_ is document_
     592                        if (tree.document is document
    583593                            append (tree); 
    584594                        else 
    585595                           tree = copy (tree); 
    586596                        return tree; 
     597                } 
     598 
     599                /*************************************************************** 
     600         
     601                        Return an xpath handle to query this node 
     602 
     603                        See also Node.document.query 
     604 
     605                ***************************************************************/ 
     606         
     607                final XmlPath!(T).NodeSet query () 
     608                { 
     609                        return document.xpath.start (this); 
    587610                } 
    588611 
     
    873896                private Node create (XmlNodeType type, T[] value) 
    874897                { 
    875                         auto node = document_.allocate; 
     898                        auto node = document.allocate; 
    876899                        node.rawValue = value; 
    877900                        node.type = type; 
     
    915938                private void migrate (Document host) 
    916939                { 
    917                         this.document_ = host; 
     940                        this.document = host; 
    918941                        foreach (attr; attributes) 
    919942                                 attr.migrate (host); 
     
    926949 
    927950/******************************************************************************* 
     951 
     952        XPath support  
     953 
     954        Provides support for common XPath axis and filtering functions, 
     955        via a native-D interface instead of typical interpreted notation. 
     956 
     957        The general idea here is to generate a NodeSet consisting of those 
     958        tree-nodes which satisfy a filtering function. The direction, or 
     959        axis, of tree traversal is governed by one of several predefined 
     960        operations. All methods facilitiate call-chaining, where each step  
     961        returns a new NodeSet instance to be operated upon. 
     962 
     963        The set of nodes themselves are collected in a freelist, avoiding 
     964        heap-activity and making good use of D array-slicing facilities. 
     965 
     966        (this needs to be a class in order to avoid forward-ref issues) 
     967 
     968*******************************************************************************/ 
     969 
     970private class XmlPath(T) 
     971{        
     972        public alias Document!(T) Doc;          /// the typed document 
     973        public alias Doc.Node Node;             /// generic document node 
     974          
     975        private Node[]          freelist; 
     976        private uint            freeIndex, 
     977                                markIndex; 
     978        private uint            recursion; 
     979 
     980        /*********************************************************************** 
     981         
     982                Prime a query 
     983 
     984                Returns a NodeSet containing just the given node, which 
     985                can then be used to cascade results into subsequent NodeSet 
     986                instances. 
     987 
     988        ***********************************************************************/ 
     989         
     990        final NodeSet start (Node root) 
     991        { 
     992                // we have to support recursion which may occur within 
     993                // a filter callback 
     994                if (recursion is 0) 
     995                   { 
     996                   if (freelist.length is 0) 
     997                       freelist.length = 256; 
     998                   freeIndex = 0; 
     999                   } 
     1000 
     1001                NodeSet set = {this}; 
     1002                auto mark = freeIndex; 
     1003                allocate(root); 
     1004                return set.assign (mark); 
     1005 
     1006        } 
     1007 
     1008        /*********************************************************************** 
     1009         
     1010                This is the meat of XPath support. All of the NodeSet 
     1011                operators exist here, in order to enable call-chaining. 
     1012 
     1013                Note that some of the axis do double-duty as a filter  
     1014                also. This is just a convenience factor, and doesn't  
     1015                change the underlying mechanisms. 
     1016 
     1017        ***********************************************************************/ 
     1018         
     1019        struct NodeSet 
     1020        { 
     1021                private XmlPath host; 
     1022                private Node[]   members; 
     1023                
     1024                /*************************************************************** 
     1025         
     1026                        Return the number of selected nodes in the set 
     1027 
     1028                ***************************************************************/ 
     1029         
     1030                uint count () 
     1031                { 
     1032                        return members.length; 
     1033                } 
     1034 
     1035                /*************************************************************** 
     1036         
     1037                        Return a set containing just the first node of 
     1038                        the current set 
     1039 
     1040                ***************************************************************/ 
     1041         
     1042                NodeSet first () 
     1043                { 
     1044                        return nth (0); 
     1045                } 
     1046 
     1047                /*************************************************************** 
     1048        
     1049                        Return a set containing just the last node of 
     1050                        the current set 
     1051 
     1052                ***************************************************************/ 
     1053         
     1054                NodeSet last () 
     1055                {        
     1056                        auto i = members.length; 
     1057                        if (i > 0) 
     1058                            --i; 
     1059                        return nth (i); 
     1060                } 
     1061 
     1062                /*************************************************************** 
     1063         
     1064                        Return a set containing just the nth node of 
     1065                        the current set 
     1066 
     1067                ***************************************************************/ 
     1068         
     1069                NodeSet opIndex (uint i) 
     1070                { 
     1071                        return nth (i); 
     1072                } 
     1073 
     1074                /*************************************************************** 
     1075         
     1076                        Return a set containing just the nth node of 
     1077                        the current set 
     1078         
     1079                ***************************************************************/ 
     1080         
     1081                NodeSet nth (uint index) 
     1082                { 
     1083                        NodeSet set = {host}; 
     1084                        auto mark = host.mark; 
     1085                        if (index < members.length) 
     1086                            host.allocate (members [index]); 
     1087                        return set.assign (mark); 
     1088                } 
     1089 
     1090                /*************************************************************** 
     1091         
     1092                        Return a set containing all child elements of the  
     1093                        nodes within this set 
     1094         
     1095                ***************************************************************/ 
     1096         
     1097                NodeSet opSlice () 
     1098                { 
     1099                        return child(); 
     1100                } 
     1101 
     1102                /*************************************************************** 
     1103         
     1104                        Return a set containing all child elements of the  
     1105                        nodes within this set, which match the given name 
     1106 
     1107                ***************************************************************/ 
     1108         
     1109                NodeSet opIndex (T[] name) 
     1110                { 
     1111                        return child (name); 
     1112                } 
     1113 
     1114                /*************************************************************** 
     1115         
     1116                        Return a set containing all child elements of the  
     1117                        nodes within this set 
     1118         
     1119                ***************************************************************/ 
     1120         
     1121                NodeSet child () 
     1122                { 
     1123                        return child ((Node node) 
     1124                                      {return node.type is XmlNodeType.Element;}); 
     1125                } 
     1126 
     1127                /*************************************************************** 
     1128         
     1129                        Return a set containing all child elements of the  
     1130                        nodes within this set, which match the given name 
     1131 
     1132                ***************************************************************/ 
     1133         
     1134                NodeSet child (T[] name) 
     1135                { 
     1136                        return child ((Node node) 
     1137                                      {return node.type is XmlNodeType.Element &&  
     1138                                              node.name == name;}); 
     1139                } 
     1140 
     1141                /*************************************************************** 
     1142         
     1143                        Return a set containing all parent elements of the  
     1144                        nodes within this set, which match the optional name 
     1145 
     1146                ***************************************************************/ 
     1147         
     1148                NodeSet parent (T[] name = null) 
     1149                { 
     1150                        return parent ((Node node) 
     1151                                      {return name.ptr is null ||  
     1152                                              node.name == name;}); 
     1153                } 
     1154 
     1155                /*************************************************************** 
     1156         
     1157                        Return a set containing all text nodes of the  
     1158                        nodes within this set 
     1159 
     1160                ***************************************************************/ 
     1161         
     1162                NodeSet text () 
     1163                { 
     1164                        return child ((Node node) 
     1165                                      {return node.type is XmlNodeType.Data;}); 
     1166                } 
     1167 
     1168                /*************************************************************** 
     1169         
     1170                        Return a set containing all text nodes of the  
     1171                        nodes within this set, which have a matching value 
     1172 
     1173                ***************************************************************/ 
     1174         
     1175                NodeSet text (T[] value) 
     1176                { 
     1177                        return child ((Node node) 
     1178                                      {return node.type is XmlNodeType.Data &&  
     1179                                              node.value == value;}); 
     1180                } 
     1181 
     1182                /*************************************************************** 
     1183         
     1184                        Return a set containing all attributes of the  
     1185                        nodes within this set, which have a matching value 
     1186 
     1187                ***************************************************************/ 
     1188         
     1189                NodeSet attribute () 
     1190                { 
     1191                        return attributes ((Node node) 
     1192                                          {return node.type is XmlNodeType.Attribute;}); 
     1193                } 
     1194 
     1195                /*************************************************************** 
     1196         
     1197                        Return a set containing all attributes of the  
     1198                        nodes within this set, which have a matching name 
     1199 
     1200                ***************************************************************/ 
     1201         
     1202                NodeSet attribute (T[] name) 
     1203                { 
     1204                        return attributes ((Node node) 
     1205                                           {return node.type is XmlNodeType.Attribute &&  
     1206                                                   node.name == name;}); 
     1207                } 
     1208 
     1209                /*************************************************************** 
     1210         
     1211                        Return a set containing all descendant elements of  
     1212                        the nodes within this set 
     1213 
     1214                ***************************************************************/ 
     1215         
     1216                NodeSet descendant () 
     1217                { 
     1218                        return descendant ((Node node) 
     1219                                           {return node.type is XmlNodeType.Element;}); 
     1220                } 
     1221 
     1222                /*************************************************************** 
     1223         
     1224                        Return a set containing all descendant elements of  
     1225                        the nodes within this set, which match the given name 
     1226 
     1227                ***************************************************************/ 
     1228         
     1229                NodeSet descendant (T[] name) 
     1230                { 
     1231                        return descendant ((Node node) 
     1232                                           {return node.type is XmlNodeType.Element &&  
     1233                                                   node.name == name;}); 
     1234                } 
     1235 
     1236                /*************************************************************** 
     1237         
     1238                        Return a set containing all ancestor elements of  
     1239                        the nodes within this set, which match the optional 
     1240                        name 
     1241 
     1242                ***************************************************************/ 
     1243         
     1244                NodeSet ancestor (T[] name = null) 
     1245                { 
     1246                        return ancestor ((Node node) 
     1247                                         {return name.ptr is null ||  
     1248                                                 node.name == name;}); 
     1249                } 
     1250 
     1251                /*************************************************************** 
     1252         
     1253                        Return a set containing all prior sibling elements of  
     1254                        the nodes within this set, which match the optional 
     1255                        name 
     1256 
     1257                ***************************************************************/ 
     1258         
     1259                NodeSet prev (T[] name = null) 
     1260                { 
     1261                        return prev ((Node node) 
     1262                                     {return node.type is XmlNodeType.Element && 
     1263                                             (name.ptr is null ||  
     1264                                              node.name == name);}); 
     1265                } 
     1266 
     1267                /*************************************************************** 
     1268         
     1269                        Return a set containing all subsequent sibling  
     1270                        elements of the nodes within this set, which  
     1271                        match the optional name 
     1272 
     1273                ***************************************************************/ 
     1274         
     1275                NodeSet next (T[] name = null) 
     1276                { 
     1277                        return next ((Node node) 
     1278                                     {return node.type is XmlNodeType.Element && 
     1279                                             (name.ptr is null ||  
     1280                                              node.name == name);}); 
     1281                } 
     1282 
     1283                /*************************************************************** 
     1284         
     1285                        Return a set containing all nodes within this set 
     1286                        which pass the filtering test 
     1287 
     1288                ***************************************************************/ 
     1289         
     1290                NodeSet filter (bool delegate(Node) filter) 
     1291                { 
     1292                        NodeSet set = {host}; 
     1293                        auto mark = host.mark; 
     1294                        foreach (member; members) 
     1295                                 test (filter, member); 
     1296                        return set.assign (mark); 
     1297                } 
     1298 
     1299                /*************************************************************** 
     1300         
     1301                        Return a set containing all child nodes of  
     1302                        the nodes within this set which pass the  
     1303                        filtering test 
     1304 
     1305                ***************************************************************/ 
     1306         
     1307                NodeSet child (bool delegate(Node) filter) 
     1308                { 
     1309                        NodeSet set = {host}; 
     1310                        auto mark = host.mark; 
     1311                        foreach (parent; members) 
     1312                                 foreach (child; parent.children) 
     1313                                          test (filter, child); 
     1314                        return set.assign (mark); 
     1315                } 
     1316 
     1317                /*************************************************************** 
     1318         
     1319                        Return a set containing all parent nodes of  
     1320                        the nodes within this set which pass the given 
     1321                        filtering test 
     1322 
     1323                ***************************************************************/ 
     1324         
     1325                NodeSet parent (bool delegate(Node) filter) 
     1326                { 
     1327                        NodeSet set = {host}; 
     1328                        auto mark = host.mark; 
     1329                        foreach (member; members) 
     1330                                { 
     1331                                auto p = member.parent; 
     1332                                if (p && p.type != XmlNodeType.Document) 
     1333                                   test (filter, p); 
     1334                                } 
     1335                        return set.assign (mark); 
     1336                } 
     1337 
     1338                /*************************************************************** 
     1339         
     1340                        Return a set containing all attribute nodes of  
     1341                        the nodes within this set which pass the given 
     1342                        filtering test 
     1343 
     1344                ***************************************************************/ 
     1345         
     1346                NodeSet attributes (bool delegate(Node) filter) 
     1347                { 
     1348                        NodeSet set = {host}; 
     1349                        auto mark = host.mark; 
     1350                        foreach (member; members) 
     1351                                 foreach (attr; member.attributes) 
     1352                                          test (filter, attr); 
     1353                        return set.assign (mark); 
     1354                } 
     1355 
     1356                /*************************************************************** 
     1357         
     1358                        Return a set containing all descendant nodes of  
     1359                        the nodes within this set, which pass the given 
     1360                        filtering test 
     1361 
     1362                ***************************************************************/ 
     1363         
     1364                NodeSet descendant (bool delegate(Node) filter) 
     1365                { 
     1366                        void traverse (Node parent) 
     1367                        { 
     1368                                 foreach (child; parent.children) 
     1369                                         { 
     1370                                         test (filter, child); 
     1371                                         traverse (child); 
     1372                                         }                                                 
     1373                        } 
     1374 
     1375                        NodeSet set = {host}; 
     1376                        auto mark = host.mark; 
     1377 
     1378                        foreach (member; members) 
     1379                                 traverse (member); 
     1380 
     1381                        return set.assign (mark); 
     1382                } 
     1383 
     1384                /*************************************************************** 
     1385         
     1386                        Return a set containing all ancestor nodes of  
     1387                        the nodes within this set, which pass the given 
     1388                        filtering test 
     1389 
     1390                ***************************************************************/ 
     1391         
     1392                NodeSet ancestor (bool delegate(Node) filter) 
     1393                { 
     1394                        void traverse (Node child) 
     1395                        { 
     1396                                auto p = child.parent_; 
     1397                                if (p && p.type != XmlNodeType.Document) 
     1398                                   { 
     1399                                   test (filter, p); 
     1400                                   traverse (p); 
     1401                                   } 
     1402                        } 
     1403 
     1404                        NodeSet set = {host}; 
     1405                        auto mark = host.mark; 
     1406 
     1407                        foreach (member; members) 
     1408                                 traverse (member); 
     1409 
     1410                        return set.assign (mark); 
     1411                } 
     1412 
     1413                /*************************************************************** 
     1414         
     1415                        Return a set containing all following siblings  
     1416                        of the ones within this set, which pass the given 
     1417                        filtering test 
     1418 
     1419                ***************************************************************/ 
     1420         
     1421                NodeSet next (bool delegate(Node) filter) 
     1422                { 
     1423                        NodeSet set = {host}; 
     1424                        auto mark = host.mark; 
     1425                        foreach (member; members) 
     1426                                { 
     1427                                auto p = member.nextSibling_; 
     1428                                while (p) 
     1429                                      { 
     1430                                      test (filter, p); 
     1431                                      p = p.nextSibling_; 
     1432                                      } 
     1433                                } 
     1434                        return set.assign (mark); 
     1435                } 
     1436 
     1437                /*************************************************************** 
     1438         
     1439                        Return a set containing all prior sibling nodes  
     1440                        of the ones within this set, which pass the given 
     1441                        filtering test 
     1442 
     1443                ***************************************************************/ 
     1444         
     1445                NodeSet prev (bool delegate(Node) filter) 
     1446                { 
     1447                        NodeSet set = {host}; 
     1448                        auto mark = host.mark; 
     1449                        foreach (member; members) 
     1450                                { 
     1451                                auto p = member.prevSibling_; 
     1452                                while (p) 
     1453                                      { 
     1454                                      test (filter, p); 
     1455                                      p = p.prevSibling_; 
     1456                                      } 
     1457                                } 
     1458                        return set.assign (mark); 
     1459                } 
     1460 
     1461                /*************************************************************** 
     1462                 
     1463                        Traverse the members of this set 
     1464 
     1465                ***************************************************************/ 
     1466         
     1467                int opApply (int delegate(inout Node) dg) 
     1468                { 
     1469                        int ret; 
     1470                        foreach (member; members) 
     1471                                 if ((ret = dg (member)) != 0)  
     1472                                      break; 
     1473                        return ret; 
     1474                } 
     1475 
     1476                /*************************************************************** 
     1477         
     1478                        Assign a slice of the freelist to this NodeSet 
     1479 
     1480                ***************************************************************/ 
     1481         
     1482                private NodeSet assign (uint mark) 
     1483                { 
     1484                        members = host.slice (mark); 
     1485                        return *this; 
     1486                } 
     1487 
     1488                /*************************************************************** 
     1489         
     1490                        Execute a filter on the given node. We have to 
     1491                        deal with potential query recusion, so we set 
     1492                        all kinda crap to recover from that 
     1493 
     1494                ***************************************************************/ 
     1495         
     1496                private void test (bool delegate(Node) filter, Node node) 
     1497                { 
     1498                        ++host.recursion; 
     1499                        auto pop = host.freeIndex; 
     1500                        auto add = filter (node); 
     1501                        host.freeIndex = pop; 
     1502                        --host.recursion; 
     1503                        if (add) 
     1504                            host.allocate (node); 
     1505                } 
     1506        } 
     1507 
     1508        /*********************************************************************** 
     1509 
     1510                Return the current freelist index 
     1511                         
     1512        ***********************************************************************/ 
     1513         
     1514        private uint mark () 
     1515        {        
     1516                return freeIndex; 
     1517        } 
     1518 
     1519        /*********************************************************************** 
     1520         
     1521                Return a slice of the freelist 
     1522 
     1523        ***********************************************************************/ 
     1524         
     1525        private Node[] slice (uint mark) 
     1526        { 
     1527                assert (mark <= freeIndex); 
     1528                return freelist [mark .. freeIndex]; 
     1529        } 
     1530 
     1531        /*********************************************************************** 
     1532         
     1533                Allocate an entry in the freelist, expanding as necessary 
     1534 
     1535        ***********************************************************************/ 
     1536         
     1537        private uint allocate (Node node) 
     1538        { 
     1539                if (freeIndex >= freelist.length) 
     1540                    freelist.length = freelist.length + freelist.length / 2; 
     1541 
     1542                freelist[freeIndex] = node; 
     1543                return ++freeIndex; 
     1544        } 
     1545} 
     1546 
     1547 
     1548 
     1549/******************************************************************************* 
     1550 
     1551        Specification for an XML serializer 
    9281552 
    9291553*******************************************************************************/ 
     
    9511575        void print (Node root, void delegate(T[][]...) emit); 
    9521576} 
     1577 
     1578 
     1579