| 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 |