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 |