OLD | NEW |
1 /* | 1 /* |
2 * pattern.c: Implemetation of the template match compilation and lookup | 2 * pattern.c: Implemetation of the template match compilation and lookup |
3 * | 3 * |
4 * Reference: | 4 * Reference: |
5 * http://www.w3.org/TR/1999/REC-xslt-19991116 | 5 * http://www.w3.org/TR/1999/REC-xslt-19991116 |
6 * | 6 * |
7 * See Copyright for the status of this software. | 7 * See Copyright for the status of this software. |
8 * | 8 * |
9 * daniel@veillard.com | 9 * daniel@veillard.com |
10 */ | 10 */ |
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 comp->steps[j].indexExtra = t; | 444 comp->steps[j].indexExtra = t; |
445 t = comp->steps[i].lenExtra; | 445 t = comp->steps[i].lenExtra; |
446 comp->steps[i].lenExtra = comp->steps[j].lenExtra; | 446 comp->steps[i].lenExtra = comp->steps[j].lenExtra; |
447 comp->steps[j].lenExtra = t; | 447 comp->steps[j].lenExtra = t; |
448 j--; | 448 j--; |
449 i++; | 449 i++; |
450 } | 450 } |
451 xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0); | 451 xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0); |
452 | 452 |
453 /* | 453 /* |
454 * detect consecutive XSLT_OP_PREDICATE indicating a direct | 454 * Detect consecutive XSLT_OP_PREDICATE and predicates on ops which |
455 * matching should be done. | 455 * haven't been optimized yet indicating a direct matching should be done. |
456 */ | 456 */ |
457 for (i = 0;i < comp->nbStep - 1;i++) { | 457 for (i = 0;i < comp->nbStep - 1;i++) { |
458 if ((comp->steps[i].op == XSLT_OP_PREDICATE) && | 458 xsltOp op = comp->steps[i].op; |
| 459 |
| 460 if ((op != XSLT_OP_ELEM) && |
| 461 (op != XSLT_OP_ALL) && |
459 (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) { | 462 (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) { |
460 | 463 |
461 comp->direct = 1; | 464 comp->direct = 1; |
462 if (comp->pattern[0] != '/') { | 465 if (comp->pattern[0] != '/') { |
463 xmlChar *query; | 466 xmlChar *query; |
464 | 467 |
465 query = xmlStrdup((const xmlChar *)"//"); | 468 query = xmlStrdup((const xmlChar *)"//"); |
466 query = xmlStrcat(query, comp->pattern); | 469 query = xmlStrcat(query, comp->pattern); |
467 | 470 |
468 xmlFree((xmlChar *) comp->pattern); | 471 xmlFree((xmlChar *) comp->pattern); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 } | 617 } |
615 } | 618 } |
616 } else { | 619 } else { |
617 } | 620 } |
618 if (nocache == 1) | 621 if (nocache == 1) |
619 xmlXPathFreeObject(list); | 622 xmlXPathFreeObject(list); |
620 return(0); | 623 return(0); |
621 } | 624 } |
622 | 625 |
623 /** | 626 /** |
| 627 * xsltTestPredicateMatch: |
| 628 * @ctxt: a XSLT process context |
| 629 * @comp: the precompiled pattern |
| 630 * @node: a node |
| 631 * @step: the predicate step |
| 632 * @sel: the previous step |
| 633 * |
| 634 * Test whether the node matches the predicate |
| 635 * |
| 636 * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure |
| 637 */ |
| 638 static int |
| 639 xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, |
| 640 xmlNodePtr node, xsltStepOpPtr step, |
| 641 xsltStepOpPtr sel) { |
| 642 xmlNodePtr oldNode; |
| 643 xmlDocPtr doc; |
| 644 int oldCS, oldCP; |
| 645 int pos = 0, len = 0; |
| 646 int isRVT; |
| 647 int match; |
| 648 |
| 649 if (step->value == NULL) |
| 650 return(0); |
| 651 if (step->comp == NULL) |
| 652 return(0); |
| 653 |
| 654 doc = node->doc; |
| 655 if (XSLT_IS_RES_TREE_FRAG(doc)) |
| 656 isRVT = 1; |
| 657 else |
| 658 isRVT = 0; |
| 659 |
| 660 /* |
| 661 * Recompute contextSize and proximityPosition. |
| 662 * |
| 663 * TODO: Make this work for additional ops. Currently, only XSLT_OP_ELEM |
| 664 * and XSLT_OP_ALL are supported. |
| 665 */ |
| 666 oldCS = ctxt->xpathCtxt->contextSize; |
| 667 oldCP = ctxt->xpathCtxt->proximityPosition; |
| 668 if ((sel != NULL) && |
| 669 (sel->op == XSLT_OP_ELEM) && |
| 670 (sel->value != NULL) && |
| 671 (node->type == XML_ELEMENT_NODE) && |
| 672 (node->parent != NULL)) { |
| 673 xmlNodePtr previous; |
| 674 int nocache = 0; |
| 675 |
| 676 previous = (xmlNodePtr) |
| 677 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); |
| 678 if ((previous != NULL) && |
| 679 (previous->parent == node->parent)) { |
| 680 /* |
| 681 * just walk back to adjust the index |
| 682 */ |
| 683 int indx = 0; |
| 684 xmlNodePtr sibling = node; |
| 685 |
| 686 while (sibling != NULL) { |
| 687 if (sibling == previous) |
| 688 break; |
| 689 if ((sibling->type == XML_ELEMENT_NODE) && |
| 690 (previous->name != NULL) && |
| 691 (sibling->name != NULL) && |
| 692 (previous->name[0] == sibling->name[0]) && |
| 693 (xmlStrEqual(previous->name, sibling->name))) |
| 694 { |
| 695 if ((sel->value2 == NULL) || |
| 696 ((sibling->ns != NULL) && |
| 697 (xmlStrEqual(sel->value2, sibling->ns->href)))) |
| 698 indx++; |
| 699 } |
| 700 sibling = sibling->prev; |
| 701 } |
| 702 if (sibling == NULL) { |
| 703 /* hum going backward in document order ... */ |
| 704 indx = 0; |
| 705 sibling = node; |
| 706 while (sibling != NULL) { |
| 707 if (sibling == previous) |
| 708 break; |
| 709 if ((sibling->type == XML_ELEMENT_NODE) && |
| 710 (previous->name != NULL) && |
| 711 (sibling->name != NULL) && |
| 712 (previous->name[0] == sibling->name[0]) && |
| 713 (xmlStrEqual(previous->name, sibling->name))) |
| 714 { |
| 715 if ((sel->value2 == NULL) || |
| 716 ((sibling->ns != NULL) && |
| 717 (xmlStrEqual(sel->value2, |
| 718 sibling->ns->href)))) |
| 719 { |
| 720 indx--; |
| 721 } |
| 722 } |
| 723 sibling = sibling->next; |
| 724 } |
| 725 } |
| 726 if (sibling != NULL) { |
| 727 pos = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) + indx; |
| 728 /* |
| 729 * If the node is in a Value Tree we need to |
| 730 * save len, but cannot cache the node! |
| 731 * (bugs 153137 and 158840) |
| 732 */ |
| 733 if (node->doc != NULL) { |
| 734 len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival); |
| 735 if (!isRVT) { |
| 736 XSLT_RUNTIME_EXTRA(ctxt, |
| 737 sel->previousExtra, ptr) = node; |
| 738 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos; |
| 739 } |
| 740 } |
| 741 } else |
| 742 pos = 0; |
| 743 } else { |
| 744 /* |
| 745 * recompute the index |
| 746 */ |
| 747 xmlNodePtr parent = node->parent; |
| 748 xmlNodePtr siblings = NULL; |
| 749 |
| 750 if (parent) siblings = parent->children; |
| 751 |
| 752 while (siblings != NULL) { |
| 753 if (siblings->type == XML_ELEMENT_NODE) { |
| 754 if (siblings == node) { |
| 755 len++; |
| 756 pos = len; |
| 757 } else if ((node->name != NULL) && |
| 758 (siblings->name != NULL) && |
| 759 (node->name[0] == siblings->name[0]) && |
| 760 (xmlStrEqual(node->name, siblings->name))) { |
| 761 if ((sel->value2 == NULL) || |
| 762 ((siblings->ns != NULL) && |
| 763 (xmlStrEqual(sel->value2, siblings->ns->href)))) |
| 764 len++; |
| 765 } |
| 766 } |
| 767 siblings = siblings->next; |
| 768 } |
| 769 if ((parent == NULL) || (node->doc == NULL)) |
| 770 nocache = 1; |
| 771 else { |
| 772 while (parent->parent != NULL) |
| 773 parent = parent->parent; |
| 774 if (((parent->type != XML_DOCUMENT_NODE) && |
| 775 (parent->type != XML_HTML_DOCUMENT_NODE)) || |
| 776 (parent != (xmlNodePtr) node->doc)) |
| 777 nocache = 1; |
| 778 } |
| 779 } |
| 780 if (pos != 0) { |
| 781 ctxt->xpathCtxt->contextSize = len; |
| 782 ctxt->xpathCtxt->proximityPosition = pos; |
| 783 /* |
| 784 * If the node is in a Value Tree we cannot |
| 785 * cache it ! |
| 786 */ |
| 787 if ((!isRVT) && (node->doc != NULL) && |
| 788 (nocache == 0)) { |
| 789 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node; |
| 790 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos; |
| 791 XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len; |
| 792 } |
| 793 } |
| 794 } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) && |
| 795 (node->type == XML_ELEMENT_NODE)) { |
| 796 xmlNodePtr previous; |
| 797 int nocache = 0; |
| 798 |
| 799 previous = (xmlNodePtr) |
| 800 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); |
| 801 if ((previous != NULL) && |
| 802 (previous->parent == node->parent)) { |
| 803 /* |
| 804 * just walk back to adjust the index |
| 805 */ |
| 806 int indx = 0; |
| 807 xmlNodePtr sibling = node; |
| 808 |
| 809 while (sibling != NULL) { |
| 810 if (sibling == previous) |
| 811 break; |
| 812 if (sibling->type == XML_ELEMENT_NODE) |
| 813 indx++; |
| 814 sibling = sibling->prev; |
| 815 } |
| 816 if (sibling == NULL) { |
| 817 /* hum going backward in document order ... */ |
| 818 indx = 0; |
| 819 sibling = node; |
| 820 while (sibling != NULL) { |
| 821 if (sibling == previous) |
| 822 break; |
| 823 if (sibling->type == XML_ELEMENT_NODE) |
| 824 indx--; |
| 825 sibling = sibling->next; |
| 826 } |
| 827 } |
| 828 if (sibling != NULL) { |
| 829 pos = XSLT_RUNTIME_EXTRA(ctxt, |
| 830 sel->indexExtra, ival) + indx; |
| 831 /* |
| 832 * If the node is in a Value Tree we cannot |
| 833 * cache it ! |
| 834 */ |
| 835 if ((node->doc != NULL) && !isRVT) { |
| 836 len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival); |
| 837 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node; |
| 838 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos; |
| 839 } |
| 840 } else |
| 841 pos = 0; |
| 842 } else { |
| 843 /* |
| 844 * recompute the index |
| 845 */ |
| 846 xmlNodePtr parent = node->parent; |
| 847 xmlNodePtr siblings = NULL; |
| 848 |
| 849 if (parent) siblings = parent->children; |
| 850 |
| 851 while (siblings != NULL) { |
| 852 if (siblings->type == XML_ELEMENT_NODE) { |
| 853 len++; |
| 854 if (siblings == node) { |
| 855 pos = len; |
| 856 } |
| 857 } |
| 858 siblings = siblings->next; |
| 859 } |
| 860 if ((parent == NULL) || (node->doc == NULL)) |
| 861 nocache = 1; |
| 862 else { |
| 863 while (parent->parent != NULL) |
| 864 parent = parent->parent; |
| 865 if (((parent->type != XML_DOCUMENT_NODE) && |
| 866 (parent->type != XML_HTML_DOCUMENT_NODE)) || |
| 867 (parent != (xmlNodePtr) node->doc)) |
| 868 nocache = 1; |
| 869 } |
| 870 } |
| 871 if (pos != 0) { |
| 872 ctxt->xpathCtxt->contextSize = len; |
| 873 ctxt->xpathCtxt->proximityPosition = pos; |
| 874 /* |
| 875 * If the node is in a Value Tree we cannot |
| 876 * cache it ! |
| 877 */ |
| 878 if ((node->doc != NULL) && (nocache == 0) && !isRVT) { |
| 879 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node; |
| 880 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos; |
| 881 XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len; |
| 882 } |
| 883 } |
| 884 } |
| 885 |
| 886 oldNode = ctxt->node; |
| 887 ctxt->node = node; |
| 888 |
| 889 match = xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, comp->nsNr); |
| 890 |
| 891 if (pos != 0) { |
| 892 ctxt->xpathCtxt->contextSize = oldCS; |
| 893 ctxt->xpathCtxt->proximityPosition = oldCP; |
| 894 } |
| 895 ctxt->node = oldNode; |
| 896 |
| 897 return match; |
| 898 } |
| 899 |
| 900 /** |
624 * xsltTestCompMatch: | 901 * xsltTestCompMatch: |
625 * @ctxt: a XSLT process context | 902 * @ctxt: a XSLT process context |
626 * @comp: the precompiled pattern | 903 * @comp: the precompiled pattern |
627 * @node: a node | 904 * @node: a node |
628 * @mode: the mode name or NULL | 905 * @mode: the mode name or NULL |
629 * @modeURI: the mode URI or NULL | 906 * @modeURI: the mode URI or NULL |
630 * | 907 * |
631 * Test whether the node matches the pattern | 908 * Test whether the node matches the pattern |
632 * | 909 * |
633 * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure | 910 * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure |
634 */ | 911 */ |
635 static int | 912 static int |
636 xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, | 913 xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, |
637 » xmlNodePtr node, const xmlChar *mode, | 914 » xmlNodePtr matchNode, const xmlChar *mode, |
638 const xmlChar *modeURI) { | 915 const xmlChar *modeURI) { |
639 int i; | 916 int i; |
| 917 xmlNodePtr node = matchNode; |
640 xsltStepOpPtr step, sel = NULL; | 918 xsltStepOpPtr step, sel = NULL; |
641 xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */ | 919 xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */ |
642 | 920 |
643 if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) { | 921 if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) { |
644 xsltTransformError(ctxt, NULL, node, | 922 xsltTransformError(ctxt, NULL, node, |
645 "xsltTestCompMatch: null arg\n"); | 923 "xsltTestCompMatch: null arg\n"); |
646 return(-1); | 924 return(-1); |
647 } | 925 } |
648 if (mode != NULL) { | 926 if (mode != NULL) { |
649 if (comp->mode == NULL) | 927 if (comp->mode == NULL) |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
847 goto rollback; | 1125 goto rollback; |
848 if (!xmlStrEqual(step->value, node->ns->href)) | 1126 if (!xmlStrEqual(step->value, node->ns->href)) |
849 goto rollback; | 1127 goto rollback; |
850 } | 1128 } |
851 break; | 1129 break; |
852 case XSLT_OP_ALL: | 1130 case XSLT_OP_ALL: |
853 if (node->type != XML_ELEMENT_NODE) | 1131 if (node->type != XML_ELEMENT_NODE) |
854 goto rollback; | 1132 goto rollback; |
855 break; | 1133 break; |
856 case XSLT_OP_PREDICATE: { | 1134 case XSLT_OP_PREDICATE: { |
857 xmlNodePtr oldNode; | |
858 xmlDocPtr doc; | |
859 int oldCS, oldCP; | |
860 int pos = 0, len = 0; | |
861 int isRVT; | |
862 | |
863 /* | 1135 /* |
864 » » * when there is cascading XSLT_OP_PREDICATE, then use a | 1136 » » * When there is cascading XSLT_OP_PREDICATE or a predicate |
| 1137 » » * after an op which hasn't been optimized yet, then use a |
865 * direct computation approach. It's not done directly | 1138 * direct computation approach. It's not done directly |
866 * at the beginning of the routine to filter out as much | 1139 * at the beginning of the routine to filter out as much |
867 * as possible this costly computation. | 1140 * as possible this costly computation. |
868 */ | 1141 */ |
869 if (comp->direct) { | 1142 if (comp->direct) { |
870 if (states.states != NULL) { | 1143 if (states.states != NULL) { |
871 /* Free the rollback states */ | 1144 /* Free the rollback states */ |
872 xmlFree(states.states); | 1145 xmlFree(states.states); |
873 } | 1146 } |
874 » » return(xsltTestCompMatchDirect(ctxt, comp, node, | 1147 » » return(xsltTestCompMatchDirect(ctxt, comp, matchNode, |
875 comp->nsList, comp->nsNr)); | 1148 comp->nsList, comp->nsNr)); |
876 } | 1149 } |
877 | 1150 |
878 » » doc = node->doc; | 1151 » » if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel)) |
879 » » if (XSLT_IS_RES_TREE_FRAG(doc)) | 1152 » » goto rollback; |
880 » » isRVT = 1; | |
881 » » else | |
882 » » isRVT = 0; | |
883 | 1153 |
884 /* | |
885 * Depending on the last selection, one may need to | |
886 * recompute contextSize and proximityPosition. | |
887 */ | |
888 oldCS = ctxt->xpathCtxt->contextSize; | |
889 oldCP = ctxt->xpathCtxt->proximityPosition; | |
890 if ((sel != NULL) && | |
891 (sel->op == XSLT_OP_ELEM) && | |
892 (sel->value != NULL) && | |
893 (node->type == XML_ELEMENT_NODE) && | |
894 (node->parent != NULL)) { | |
895 xmlNodePtr previous; | |
896 int nocache = 0; | |
897 | |
898 previous = (xmlNodePtr) | |
899 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); | |
900 if ((previous != NULL) && | |
901 (previous->parent == node->parent)) { | |
902 /* | |
903 * just walk back to adjust the index | |
904 */ | |
905 int indx = 0; | |
906 xmlNodePtr sibling = node; | |
907 | |
908 while (sibling != NULL) { | |
909 if (sibling == previous) | |
910 break; | |
911 if ((sibling->type == XML_ELEMENT_NODE) && | |
912 (previous->name != NULL) && | |
913 (sibling->name != NULL) && | |
914 (previous->name[0] == sibling->name[0]) && | |
915 (xmlStrEqual(previous->name, sibling->name))) | |
916 { | |
917 if ((sel->value2 == NULL) || | |
918 ((sibling->ns != NULL) && | |
919 (xmlStrEqual(sel->value2, | |
920 sibling->ns->href)))) | |
921 indx++; | |
922 } | |
923 sibling = sibling->prev; | |
924 } | |
925 if (sibling == NULL) { | |
926 /* hum going backward in document order ... */ | |
927 indx = 0; | |
928 sibling = node; | |
929 while (sibling != NULL) { | |
930 if (sibling == previous) | |
931 break; | |
932 if ((sibling->type == XML_ELEMENT_NODE) && | |
933 (previous->name != NULL) && | |
934 (sibling->name != NULL) && | |
935 (previous->name[0] == sibling->name[0]) && | |
936 (xmlStrEqual(previous->name, sibling->name))
) | |
937 { | |
938 if ((sel->value2 == NULL) || | |
939 ((sibling->ns != NULL) && | |
940 (xmlStrEqual(sel->value2, | |
941 sibling->ns->href)))) | |
942 { | |
943 indx--; | |
944 } | |
945 } | |
946 sibling = sibling->next; | |
947 } | |
948 } | |
949 if (sibling != NULL) { | |
950 pos = XSLT_RUNTIME_EXTRA(ctxt, | |
951 sel->indexExtra, ival) + indx; | |
952 /* | |
953 * If the node is in a Value Tree we need to | |
954 * save len, but cannot cache the node! | |
955 * (bugs 153137 and 158840) | |
956 */ | |
957 if (node->doc != NULL) { | |
958 len = XSLT_RUNTIME_EXTRA(ctxt, | |
959 sel->lenExtra, ival); | |
960 if (!isRVT) { | |
961 XSLT_RUNTIME_EXTRA(ctxt, | |
962 sel->previousExtra, ptr) = node; | |
963 XSLT_RUNTIME_EXTRA(ctxt, | |
964 sel->indexExtra, ival) = pos; | |
965 } | |
966 } | |
967 } else | |
968 pos = 0; | |
969 } else { | |
970 /* | |
971 * recompute the index | |
972 */ | |
973 xmlNodePtr parent = node->parent; | |
974 xmlNodePtr siblings = NULL; | |
975 | |
976 if (parent) siblings = parent->children; | |
977 | |
978 while (siblings != NULL) { | |
979 if (siblings->type == XML_ELEMENT_NODE) { | |
980 if (siblings == node) { | |
981 len++; | |
982 pos = len; | |
983 } else if ((node->name != NULL) && | |
984 (siblings->name != NULL) && | |
985 (node->name[0] == siblings->name[0]) && | |
986 (xmlStrEqual(node->name, siblings->name))) { | |
987 if ((sel->value2 == NULL) || | |
988 ((siblings->ns != NULL) && | |
989 (xmlStrEqual(sel->value2, | |
990 siblings->ns->href)))) | |
991 len++; | |
992 } | |
993 } | |
994 siblings = siblings->next; | |
995 } | |
996 if ((parent == NULL) || (node->doc == NULL)) | |
997 nocache = 1; | |
998 else { | |
999 while (parent->parent != NULL) | |
1000 parent = parent->parent; | |
1001 if (((parent->type != XML_DOCUMENT_NODE) && | |
1002 (parent->type != XML_HTML_DOCUMENT_NODE)) || | |
1003 (parent != (xmlNodePtr) node->doc)) | |
1004 nocache = 1; | |
1005 } | |
1006 } | |
1007 if (pos != 0) { | |
1008 ctxt->xpathCtxt->contextSize = len; | |
1009 ctxt->xpathCtxt->proximityPosition = pos; | |
1010 /* | |
1011 * If the node is in a Value Tree we cannot | |
1012 * cache it ! | |
1013 */ | |
1014 if ((!isRVT) && (node->doc != NULL) && | |
1015 (nocache == 0)) { | |
1016 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = | |
1017 node; | |
1018 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = | |
1019 pos; | |
1020 XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = | |
1021 len; | |
1022 } | |
1023 } | |
1024 } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) && | |
1025 (node->type == XML_ELEMENT_NODE)) { | |
1026 xmlNodePtr previous; | |
1027 int nocache = 0; | |
1028 | |
1029 previous = (xmlNodePtr) | |
1030 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); | |
1031 if ((previous != NULL) && | |
1032 (previous->parent == node->parent)) { | |
1033 /* | |
1034 * just walk back to adjust the index | |
1035 */ | |
1036 int indx = 0; | |
1037 xmlNodePtr sibling = node; | |
1038 | |
1039 while (sibling != NULL) { | |
1040 if (sibling == previous) | |
1041 break; | |
1042 if (sibling->type == XML_ELEMENT_NODE) | |
1043 indx++; | |
1044 sibling = sibling->prev; | |
1045 } | |
1046 if (sibling == NULL) { | |
1047 /* hum going backward in document order ... */ | |
1048 indx = 0; | |
1049 sibling = node; | |
1050 while (sibling != NULL) { | |
1051 if (sibling == previous) | |
1052 break; | |
1053 if (sibling->type == XML_ELEMENT_NODE) | |
1054 indx--; | |
1055 sibling = sibling->next; | |
1056 } | |
1057 } | |
1058 if (sibling != NULL) { | |
1059 pos = XSLT_RUNTIME_EXTRA(ctxt, | |
1060 sel->indexExtra, ival) + indx; | |
1061 /* | |
1062 * If the node is in a Value Tree we cannot | |
1063 * cache it ! | |
1064 */ | |
1065 if ((node->doc != NULL) && !isRVT) { | |
1066 len = XSLT_RUNTIME_EXTRA(ctxt, | |
1067 sel->lenExtra, ival); | |
1068 XSLT_RUNTIME_EXTRA(ctxt, | |
1069 sel->previousExtra, ptr) = node; | |
1070 XSLT_RUNTIME_EXTRA(ctxt, | |
1071 sel->indexExtra, ival) = pos; | |
1072 } | |
1073 } else | |
1074 pos = 0; | |
1075 } else { | |
1076 /* | |
1077 * recompute the index | |
1078 */ | |
1079 xmlNodePtr parent = node->parent; | |
1080 xmlNodePtr siblings = NULL; | |
1081 | |
1082 if (parent) siblings = parent->children; | |
1083 | |
1084 while (siblings != NULL) { | |
1085 if (siblings->type == XML_ELEMENT_NODE) { | |
1086 len++; | |
1087 if (siblings == node) { | |
1088 pos = len; | |
1089 } | |
1090 } | |
1091 siblings = siblings->next; | |
1092 } | |
1093 if ((parent == NULL) || (node->doc == NULL)) | |
1094 nocache = 1; | |
1095 else { | |
1096 while (parent->parent != NULL) | |
1097 parent = parent->parent; | |
1098 if (((parent->type != XML_DOCUMENT_NODE) && | |
1099 (parent->type != XML_HTML_DOCUMENT_NODE)) || | |
1100 (parent != (xmlNodePtr) node->doc)) | |
1101 nocache = 1; | |
1102 } | |
1103 } | |
1104 if (pos != 0) { | |
1105 ctxt->xpathCtxt->contextSize = len; | |
1106 ctxt->xpathCtxt->proximityPosition = pos; | |
1107 /* | |
1108 * If the node is in a Value Tree we cannot | |
1109 * cache it ! | |
1110 */ | |
1111 if ((node->doc != NULL) && (nocache == 0) && !isRVT) { | |
1112 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = | |
1113 node; | |
1114 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = | |
1115 pos; | |
1116 XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = | |
1117 len; | |
1118 } | |
1119 } | |
1120 } | |
1121 oldNode = ctxt->node; | |
1122 ctxt->node = node; | |
1123 | |
1124 if (step->value == NULL) | |
1125 goto wrong_index; | |
1126 if (step->comp == NULL) | |
1127 goto wrong_index; | |
1128 | |
1129 if (!xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, | |
1130 comp->nsNr)) | |
1131 goto wrong_index; | |
1132 | |
1133 if (pos != 0) { | |
1134 ctxt->xpathCtxt->contextSize = oldCS; | |
1135 ctxt->xpathCtxt->proximityPosition = oldCP; | |
1136 } | |
1137 ctxt->node = oldNode; | |
1138 break; | 1154 break; |
1139 wrong_index: | |
1140 if (pos != 0) { | |
1141 ctxt->xpathCtxt->contextSize = oldCS; | |
1142 ctxt->xpathCtxt->proximityPosition = oldCP; | |
1143 } | |
1144 ctxt->node = oldNode; | |
1145 goto rollback; | |
1146 } | 1155 } |
1147 case XSLT_OP_PI: | 1156 case XSLT_OP_PI: |
1148 if (node->type != XML_PI_NODE) | 1157 if (node->type != XML_PI_NODE) |
1149 goto rollback; | 1158 goto rollback; |
1150 if (step->value != NULL) { | 1159 if (step->value != NULL) { |
1151 if (!xmlStrEqual(step->value, node->name)) | 1160 if (!xmlStrEqual(step->value, node->name)) |
1152 goto rollback; | 1161 goto rollback; |
1153 } | 1162 } |
1154 break; | 1163 break; |
1155 case XSLT_OP_COMMENT: | 1164 case XSLT_OP_COMMENT: |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1417 lit = xsltScanLiteral(ctxt); | 1426 lit = xsltScanLiteral(ctxt); |
1418 if (ctxt->error) { | 1427 if (ctxt->error) { |
1419 xsltTransformError(NULL, NULL, NULL, | 1428 xsltTransformError(NULL, NULL, NULL, |
1420 "xsltCompileIdKeyPattern : Literal expected\n"); | 1429 "xsltCompileIdKeyPattern : Literal expected\n"); |
1421 return; | 1430 return; |
1422 } | 1431 } |
1423 SKIP_BLANKS; | 1432 SKIP_BLANKS; |
1424 if (CUR != ',') { | 1433 if (CUR != ',') { |
1425 xsltTransformError(NULL, NULL, NULL, | 1434 xsltTransformError(NULL, NULL, NULL, |
1426 "xsltCompileIdKeyPattern : , expected\n"); | 1435 "xsltCompileIdKeyPattern : , expected\n"); |
| 1436 xmlFree(lit); |
1427 ctxt->error = 1; | 1437 ctxt->error = 1; |
1428 return; | 1438 return; |
1429 } | 1439 } |
1430 NEXT; | 1440 NEXT; |
1431 SKIP_BLANKS; | 1441 SKIP_BLANKS; |
1432 lit2 = xsltScanLiteral(ctxt); | 1442 lit2 = xsltScanLiteral(ctxt); |
1433 if (ctxt->error) { | 1443 if (ctxt->error) { |
1434 xsltTransformError(NULL, NULL, NULL, | 1444 xsltTransformError(NULL, NULL, NULL, |
1435 "xsltCompileIdKeyPattern : Literal expected\n"); | 1445 "xsltCompileIdKeyPattern : Literal expected\n"); |
1436 xmlFree(lit); | 1446 xmlFree(lit); |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2073 const xmlChar *mode, const xmlChar *modeURI) { | 2083 const xmlChar *mode, const xmlChar *modeURI) { |
2074 xsltCompMatchPtr pat, list, next; | 2084 xsltCompMatchPtr pat, list, next; |
2075 /* | 2085 /* |
2076 * 'top' will point to style->xxxMatch ptr - declaring as 'void' | 2086 * 'top' will point to style->xxxMatch ptr - declaring as 'void' |
2077 * avoids gcc 'type-punned pointer' warning. | 2087 * avoids gcc 'type-punned pointer' warning. |
2078 */ | 2088 */ |
2079 void **top = NULL; | 2089 void **top = NULL; |
2080 const xmlChar *name = NULL; | 2090 const xmlChar *name = NULL; |
2081 float priority; /* the priority */ | 2091 float priority; /* the priority */ |
2082 | 2092 |
2083 if ((style == NULL) || (cur == NULL) || (cur->match == NULL)) | 2093 if ((style == NULL) || (cur == NULL)) |
2084 return(-1); | 2094 return(-1); |
2085 | 2095 |
| 2096 /* Register named template */ |
| 2097 if (cur->name != NULL) { |
| 2098 if (style->namedTemplates == NULL) { |
| 2099 style->namedTemplates = xmlHashCreate(10); |
| 2100 if (style->namedTemplates == NULL) |
| 2101 return(-1); |
| 2102 } |
| 2103 else { |
| 2104 void *dup = xmlHashLookup2(style->namedTemplates, cur->name, |
| 2105 cur->nameURI); |
| 2106 if (dup != NULL) { |
| 2107 xsltTransformError(NULL, style, NULL, |
| 2108 "xsl:template: error duplicate name '%s'\n", |
| 2109 cur->name); |
| 2110 style->errors++; |
| 2111 return(-1); |
| 2112 } |
| 2113 } |
| 2114 |
| 2115 xmlHashAddEntry2(style->namedTemplates, cur->name, cur->nameURI, cur); |
| 2116 } |
| 2117 |
| 2118 if (cur->match == NULL) |
| 2119 return(0); |
| 2120 |
2086 priority = cur->priority; | 2121 priority = cur->priority; |
2087 pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem, | 2122 pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem, |
2088 style, NULL, 1); | 2123 style, NULL, 1); |
2089 if (pat == NULL) | 2124 if (pat == NULL) |
2090 return(-1); | 2125 return(-1); |
2091 while (pat) { | 2126 while (pat) { |
2092 next = pat->next; | 2127 next = pat->next; |
2093 pat->next = NULL; | 2128 pat->next = NULL; |
2094 name = NULL; | 2129 name = NULL; |
2095 | 2130 |
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2545 if (style->attrMatch != NULL) | 2580 if (style->attrMatch != NULL) |
2546 xsltFreeCompMatchList(style->attrMatch); | 2581 xsltFreeCompMatchList(style->attrMatch); |
2547 if (style->parentMatch != NULL) | 2582 if (style->parentMatch != NULL) |
2548 xsltFreeCompMatchList(style->parentMatch); | 2583 xsltFreeCompMatchList(style->parentMatch); |
2549 if (style->textMatch != NULL) | 2584 if (style->textMatch != NULL) |
2550 xsltFreeCompMatchList(style->textMatch); | 2585 xsltFreeCompMatchList(style->textMatch); |
2551 if (style->piMatch != NULL) | 2586 if (style->piMatch != NULL) |
2552 xsltFreeCompMatchList(style->piMatch); | 2587 xsltFreeCompMatchList(style->piMatch); |
2553 if (style->commentMatch != NULL) | 2588 if (style->commentMatch != NULL) |
2554 xsltFreeCompMatchList(style->commentMatch); | 2589 xsltFreeCompMatchList(style->commentMatch); |
| 2590 if (style->namedTemplates != NULL) |
| 2591 xmlHashFree(style->namedTemplates, NULL); |
2555 } | 2592 } |
2556 | 2593 |
OLD | NEW |