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