| OLD | NEW |
| 1 /* | 1 /* |
| 2 * numbers.c: Implementation of the XSLT number functions | 2 * numbers.c: Implementation of the XSLT number functions |
| 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 * Bjorn Reese <breese@users.sourceforge.net> | 10 * Bjorn Reese <breese@users.sourceforge.net> |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 | 525 |
| 526 /* | 526 /* |
| 527 * Handle final non-alphanumeric token | 527 * Handle final non-alphanumeric token |
| 528 */ | 528 */ |
| 529 if (tokens->end != NULL) | 529 if (tokens->end != NULL) |
| 530 xmlBufferCat(buffer, tokens->end); | 530 xmlBufferCat(buffer, tokens->end); |
| 531 | 531 |
| 532 } | 532 } |
| 533 | 533 |
| 534 static int | 534 static int |
| 535 xsltTestCompMatchCount(xsltTransformContextPtr context, |
| 536 xmlNodePtr node, |
| 537 xsltCompMatchPtr countPat, |
| 538 xmlNodePtr cur) |
| 539 { |
| 540 if (countPat != NULL) { |
| 541 return xsltTestCompMatchList(context, node, countPat); |
| 542 } |
| 543 else { |
| 544 /* |
| 545 * 7.7 Numbering |
| 546 * |
| 547 * If count attribute is not specified, then it defaults to the |
| 548 * pattern that matches any node with the same node type as the |
| 549 * current node and, if the current node has an expanded-name, with |
| 550 * the same expanded-name as the current node. |
| 551 */ |
| 552 if (node->type != cur->type) |
| 553 return 0; |
| 554 if (node->type == XML_NAMESPACE_DECL) |
| 555 /* |
| 556 * Namespace nodes have no preceding siblings and no parents |
| 557 * that are namespace nodes. This means that node == cur. |
| 558 */ |
| 559 return 1; |
| 560 /* TODO: Skip node types without expanded names like text nodes. */ |
| 561 if (!xmlStrEqual(node->name, cur->name)) |
| 562 return 0; |
| 563 if (node->ns == cur->ns) |
| 564 return 1; |
| 565 if ((node->ns == NULL) || (cur->ns == NULL)) |
| 566 return 0; |
| 567 return (xmlStrEqual(node->ns->href, cur->ns->href)); |
| 568 } |
| 569 } |
| 570 |
| 571 static int |
| 535 xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context, | 572 xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context, |
| 536 xmlNodePtr node, | 573 xmlNodePtr node, |
| 537 xsltCompMatchPtr countPat, | 574 xsltCompMatchPtr countPat, |
| 538 xsltCompMatchPtr fromPat, | 575 xsltCompMatchPtr fromPat, |
| 539 » » » double *array, | 576 » » » double *array) |
| 540 » » » xmlDocPtr doc, | |
| 541 » » » xmlNodePtr elem) | |
| 542 { | 577 { |
| 543 int amount = 0; | 578 int amount = 0; |
| 544 int cnt = 0; | 579 int cnt = 0; |
| 545 xmlNodePtr cur; | 580 xmlNodePtr cur; |
| 546 | 581 |
| 547 /* select the starting node */ | 582 /* select the starting node */ |
| 548 switch (node->type) { | 583 switch (node->type) { |
| 549 case XML_ELEMENT_NODE: | 584 case XML_ELEMENT_NODE: |
| 550 cur = node; | 585 cur = node; |
| 551 break; | 586 break; |
| 552 case XML_ATTRIBUTE_NODE: | 587 case XML_ATTRIBUTE_NODE: |
| 553 cur = ((xmlAttrPtr) node)->parent; | 588 cur = ((xmlAttrPtr) node)->parent; |
| 554 break; | 589 break; |
| 555 case XML_TEXT_NODE: | 590 case XML_TEXT_NODE: |
| 556 case XML_PI_NODE: | 591 case XML_PI_NODE: |
| 557 case XML_COMMENT_NODE: | 592 case XML_COMMENT_NODE: |
| 558 cur = node->parent; | 593 cur = node->parent; |
| 559 break; | 594 break; |
| 560 default: | 595 default: |
| 561 cur = NULL; | 596 cur = NULL; |
| 562 break; | 597 break; |
| 563 } | 598 } |
| 564 | 599 |
| 565 while (cur != NULL) { | 600 while (cur != NULL) { |
| 566 /* process current node */ | 601 /* process current node */ |
| 567 » if (countPat == NULL) { | 602 » if (xsltTestCompMatchCount(context, cur, countPat, node)) |
| 568 » if ((node->type == cur->type) && | 603 » cnt++; |
| 569 » » /* FIXME: must use expanded-name instead of local name */ | |
| 570 » » xmlStrEqual(node->name, cur->name)) { | |
| 571 » » if ((node->ns == cur->ns) || | |
| 572 » » ((node->ns != NULL) && | |
| 573 » » » (cur->ns != NULL) && | |
| 574 » » (xmlStrEqual(node->ns->href, | |
| 575 » » cur->ns->href) ))) | |
| 576 » » cnt++; | |
| 577 » } | |
| 578 » } else { | |
| 579 » if (xsltTestCompMatchList(context, cur, countPat)) | |
| 580 » » cnt++; | |
| 581 » } | |
| 582 if ((fromPat != NULL) && | 604 if ((fromPat != NULL) && |
| 583 xsltTestCompMatchList(context, cur, fromPat)) { | 605 xsltTestCompMatchList(context, cur, fromPat)) { |
| 584 break; /* while */ | 606 break; /* while */ |
| 585 } | 607 } |
| 586 | 608 |
| 587 /* Skip to next preceding or ancestor */ | 609 /* Skip to next preceding or ancestor */ |
| 588 if ((cur->type == XML_DOCUMENT_NODE) || | 610 if ((cur->type == XML_DOCUMENT_NODE) || |
| 589 #ifdef LIBXML_DOCB_ENABLED | 611 #ifdef LIBXML_DOCB_ENABLED |
| 590 (cur->type == XML_DOCB_DOCUMENT_NODE) || | 612 (cur->type == XML_DOCB_DOCUMENT_NODE) || |
| 591 #endif | 613 #endif |
| (...skipping 16 matching lines...) Expand all Loading... |
| 608 | 630 |
| 609 return(amount); | 631 return(amount); |
| 610 } | 632 } |
| 611 | 633 |
| 612 static int | 634 static int |
| 613 xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context, | 635 xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context, |
| 614 xmlNodePtr node, | 636 xmlNodePtr node, |
| 615 xsltCompMatchPtr countPat, | 637 xsltCompMatchPtr countPat, |
| 616 xsltCompMatchPtr fromPat, | 638 xsltCompMatchPtr fromPat, |
| 617 double *array, | 639 double *array, |
| 618 » » » » int max, | 640 » » » » int max) |
| 619 » » » » xmlDocPtr doc, | |
| 620 » » » » xmlNodePtr elem) | |
| 621 { | 641 { |
| 622 int amount = 0; | 642 int amount = 0; |
| 623 int cnt; | 643 int cnt; |
| 624 xmlNodePtr ancestor; | 644 xmlNodePtr ancestor; |
| 625 xmlNodePtr preceding; | 645 xmlNodePtr preceding; |
| 626 xmlXPathParserContextPtr parser; | 646 xmlXPathParserContextPtr parser; |
| 627 | 647 |
| 628 context->xpathCtxt->node = node; | 648 context->xpathCtxt->node = node; |
| 629 parser = xmlXPathNewParserContext(NULL, context->xpathCtxt); | 649 parser = xmlXPathNewParserContext(NULL, context->xpathCtxt); |
| 630 if (parser) { | 650 if (parser) { |
| 631 /* ancestor-or-self::*[count] */ | 651 /* ancestor-or-self::*[count] */ |
| 632 for (ancestor = node; | 652 for (ancestor = node; |
| 633 (ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE); | 653 (ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE); |
| 634 ancestor = xmlXPathNextAncestor(parser, ancestor)) { | 654 ancestor = xmlXPathNextAncestor(parser, ancestor)) { |
| 635 | 655 |
| 636 if ((fromPat != NULL) && | 656 if ((fromPat != NULL) && |
| 637 xsltTestCompMatchList(context, ancestor, fromPat)) | 657 xsltTestCompMatchList(context, ancestor, fromPat)) |
| 638 break; /* for */ | 658 break; /* for */ |
| 639 | 659 |
| 640 » if ((countPat == NULL && node->type == ancestor->type && | 660 » if (xsltTestCompMatchCount(context, ancestor, countPat, node)) { |
| 641 » » xmlStrEqual(node->name, ancestor->name)) || | |
| 642 » » xsltTestCompMatchList(context, ancestor, countPat)) { | |
| 643 /* count(preceding-sibling::*) */ | 661 /* count(preceding-sibling::*) */ |
| 644 » » cnt = 0; | 662 » » cnt = 1; |
| 645 » » for (preceding = ancestor; | 663 » » for (preceding = |
| 664 xmlXPathNextPrecedingSibling(parser, ancestor); |
| 646 preceding != NULL; | 665 preceding != NULL; |
| 647 preceding = | 666 preceding = |
| 648 xmlXPathNextPrecedingSibling(parser, preceding)) { | 667 xmlXPathNextPrecedingSibling(parser, preceding)) { |
| 649 » » if (countPat == NULL) { | 668 |
| 650 » » » if ((preceding->type == ancestor->type) && | 669 » if (xsltTestCompMatchCount(context, preceding, countPat, |
| 651 » » » xmlStrEqual(preceding->name, ancestor->name)){ | 670 node)) |
| 652 » » » if ((preceding->ns == ancestor->ns) || | 671 » » » cnt++; |
| 653 » » » ((preceding->ns != NULL) && | |
| 654 » » » » (ancestor->ns != NULL) && | |
| 655 » » » (xmlStrEqual(preceding->ns->href, | |
| 656 » » » ancestor->ns->href) ))) | |
| 657 » » » cnt++; | |
| 658 » » » } | |
| 659 » » } else { | |
| 660 » » » if (xsltTestCompMatchList(context, preceding, | |
| 661 » » » » countPat)) | |
| 662 » » » cnt++; | |
| 663 » » } | |
| 664 } | 672 } |
| 665 array[amount++] = (double)cnt; | 673 array[amount++] = (double)cnt; |
| 666 if (amount >= max) | 674 if (amount >= max) |
| 667 break; /* for */ | 675 break; /* for */ |
| 668 } | 676 } |
| 669 } | 677 } |
| 670 xmlXPathFreeParserContext(parser); | 678 xmlXPathFreeParserContext(parser); |
| 671 } | 679 } |
| 672 return amount; | 680 return amount; |
| 673 } | 681 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 */ | 718 */ |
| 711 void | 719 void |
| 712 xsltNumberFormat(xsltTransformContextPtr ctxt, | 720 xsltNumberFormat(xsltTransformContextPtr ctxt, |
| 713 xsltNumberDataPtr data, | 721 xsltNumberDataPtr data, |
| 714 xmlNodePtr node) | 722 xmlNodePtr node) |
| 715 { | 723 { |
| 716 xmlBufferPtr output = NULL; | 724 xmlBufferPtr output = NULL; |
| 717 int amount, i; | 725 int amount, i; |
| 718 double number; | 726 double number; |
| 719 xsltFormat tokens; | 727 xsltFormat tokens; |
| 720 int tempformat = 0; | |
| 721 | 728 |
| 722 if ((data->format == NULL) && (data->has_format != 0)) { | 729 if (data->format != NULL) { |
| 723 » data->format = xsltEvalAttrValueTemplate(ctxt, data->node, | 730 xsltNumberFormatTokenize(data->format, &tokens); |
| 731 } |
| 732 else { |
| 733 xmlChar *format; |
| 734 |
| 735 » /* The format needs to be recomputed each time */ |
| 736 if (data->has_format == 0) |
| 737 return; |
| 738 » format = xsltEvalAttrValueTemplate(ctxt, data->node, |
| 724 (const xmlChar *) "format", | 739 (const xmlChar *) "format", |
| 725 XSLT_NAMESPACE); | 740 XSLT_NAMESPACE); |
| 726 » tempformat = 1; | 741 if (format == NULL) |
| 727 } | 742 return; |
| 728 if (data->format == NULL) { | 743 xsltNumberFormatTokenize(format, &tokens); |
| 729 » return; | 744 » xmlFree(format); |
| 730 } | 745 } |
| 731 | 746 |
| 732 output = xmlBufferCreate(); | 747 output = xmlBufferCreate(); |
| 733 if (output == NULL) | 748 if (output == NULL) |
| 734 goto XSLT_NUMBER_FORMAT_END; | 749 goto XSLT_NUMBER_FORMAT_END; |
| 735 | 750 |
| 736 xsltNumberFormatTokenize(data->format, &tokens); | |
| 737 | |
| 738 /* | 751 /* |
| 739 * Evaluate the XPath expression to find the value(s) | 752 * Evaluate the XPath expression to find the value(s) |
| 740 */ | 753 */ |
| 741 if (data->value) { | 754 if (data->value) { |
| 742 amount = xsltNumberFormatGetValue(ctxt->xpathCtxt, | 755 amount = xsltNumberFormatGetValue(ctxt->xpathCtxt, |
| 743 node, | 756 node, |
| 744 data->value, | 757 data->value, |
| 745 &number); | 758 &number); |
| 746 if (amount == 1) { | 759 if (amount == 1) { |
| 747 xsltNumberFormatInsertNumbers(data, | 760 xsltNumberFormatInsertNumbers(data, |
| 748 &number, | 761 &number, |
| 749 1, | 762 1, |
| 750 &tokens, | 763 &tokens, |
| 751 output); | 764 output); |
| 752 } | 765 } |
| 753 | 766 |
| 754 } else if (data->level) { | 767 } else if (data->level) { |
| 755 | 768 |
| 756 if (xmlStrEqual(data->level, (const xmlChar *) "single")) { | 769 if (xmlStrEqual(data->level, (const xmlChar *) "single")) { |
| 757 amount = xsltNumberFormatGetMultipleLevel(ctxt, | 770 amount = xsltNumberFormatGetMultipleLevel(ctxt, |
| 758 node, | 771 node, |
| 759 data->countPat, | 772 data->countPat, |
| 760 data->fromPat, | 773 data->fromPat, |
| 761 &number, | 774 &number, |
| 762 » » » » » » 1, | 775 » » » » » » 1); |
| 763 » » » » » » data->doc, | |
| 764 » » » » » » data->node); | |
| 765 if (amount == 1) { | 776 if (amount == 1) { |
| 766 xsltNumberFormatInsertNumbers(data, | 777 xsltNumberFormatInsertNumbers(data, |
| 767 &number, | 778 &number, |
| 768 1, | 779 1, |
| 769 &tokens, | 780 &tokens, |
| 770 output); | 781 output); |
| 771 } | 782 } |
| 772 } else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) { | 783 } else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) { |
| 773 double numarray[1024]; | 784 double numarray[1024]; |
| 774 int max = sizeof(numarray)/sizeof(numarray[0]); | 785 int max = sizeof(numarray)/sizeof(numarray[0]); |
| 775 amount = xsltNumberFormatGetMultipleLevel(ctxt, | 786 amount = xsltNumberFormatGetMultipleLevel(ctxt, |
| 776 node, | 787 node, |
| 777 data->countPat, | 788 data->countPat, |
| 778 data->fromPat, | 789 data->fromPat, |
| 779 numarray, | 790 numarray, |
| 780 » » » » » » max, | 791 » » » » » » max); |
| 781 » » » » » » data->doc, | |
| 782 » » » » » » data->node); | |
| 783 if (amount > 0) { | 792 if (amount > 0) { |
| 784 xsltNumberFormatInsertNumbers(data, | 793 xsltNumberFormatInsertNumbers(data, |
| 785 numarray, | 794 numarray, |
| 786 amount, | 795 amount, |
| 787 &tokens, | 796 &tokens, |
| 788 output); | 797 output); |
| 789 } | 798 } |
| 790 } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) { | 799 } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) { |
| 791 amount = xsltNumberFormatGetAnyLevel(ctxt, | 800 amount = xsltNumberFormatGetAnyLevel(ctxt, |
| 792 node, | 801 node, |
| 793 data->countPat, | 802 data->countPat, |
| 794 data->fromPat, | 803 data->fromPat, |
| 795 » » » » » » &number, | 804 » » » » » » &number); |
| 796 » » » » » » data->doc, | |
| 797 » » » » » » data->node); | |
| 798 if (amount > 0) { | 805 if (amount > 0) { |
| 799 xsltNumberFormatInsertNumbers(data, | 806 xsltNumberFormatInsertNumbers(data, |
| 800 &number, | 807 &number, |
| 801 1, | 808 1, |
| 802 &tokens, | 809 &tokens, |
| 803 output); | 810 output); |
| 804 } | 811 } |
| 805 } | 812 } |
| 806 } | 813 } |
| 807 /* Insert number as text node */ | 814 /* Insert number as text node */ |
| 808 xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0); | 815 xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0); |
| 809 | 816 |
| 817 xmlBufferFree(output); |
| 818 |
| 819 XSLT_NUMBER_FORMAT_END: |
| 810 if (tokens.start != NULL) | 820 if (tokens.start != NULL) |
| 811 xmlFree(tokens.start); | 821 xmlFree(tokens.start); |
| 812 if (tokens.end != NULL) | 822 if (tokens.end != NULL) |
| 813 xmlFree(tokens.end); | 823 xmlFree(tokens.end); |
| 814 for (i = 0;i < tokens.nTokens;i++) { | 824 for (i = 0;i < tokens.nTokens;i++) { |
| 815 if (tokens.tokens[i].separator != NULL) | 825 if (tokens.tokens[i].separator != NULL) |
| 816 xmlFree(tokens.tokens[i].separator); | 826 xmlFree(tokens.tokens[i].separator); |
| 817 } | 827 } |
| 818 | |
| 819 XSLT_NUMBER_FORMAT_END: | |
| 820 if (tempformat == 1) { | |
| 821 /* The format need to be recomputed each time */ | |
| 822 data->format = NULL; | |
| 823 } | |
| 824 if (output != NULL) | |
| 825 xmlBufferFree(output); | |
| 826 } | 828 } |
| 827 | 829 |
| 828 static int | 830 static int |
| 829 xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltForma
tNumberInfoPtr info) | 831 xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltForma
tNumberInfoPtr info) |
| 830 { | 832 { |
| 831 int count=0; /* will hold total length of prefix/suffix */ | 833 int count=0; /* will hold total length of prefix/suffix */ |
| 832 int len; | 834 int len; |
| 833 | 835 |
| 834 while (1) { | 836 while (1) { |
| 835 /* | 837 /* |
| (...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1319 j += len - 1; /* length of symbol less length of escape */ | 1321 j += len - 1; /* length of symbol less length of escape */ |
| 1320 } else | 1322 } else |
| 1321 xmlBufferAdd(buffer, &pchar, 1); | 1323 xmlBufferAdd(buffer, &pchar, 1); |
| 1322 } | 1324 } |
| 1323 | 1325 |
| 1324 *result = xmlStrdup(xmlBufferContent(buffer)); | 1326 *result = xmlStrdup(xmlBufferContent(buffer)); |
| 1325 xmlBufferFree(buffer); | 1327 xmlBufferFree(buffer); |
| 1326 return status; | 1328 return status; |
| 1327 } | 1329 } |
| 1328 | 1330 |
| OLD | NEW |