├── test_uri ├── t ├── test_new_features_3_22.xml ├── test_with_lwp.xml ├── test4.t ├── test_with_lwp_not_wf.xml ├── test_xml_split │ ├── test_xml_split_expected-1-01.xml │ ├── test_xml_split_expected-1-02.xml │ ├── test_xml_split_expected-1-03.xml │ ├── test_xml_split_expected-10-01.xml │ ├── test_xml_split_expected-10-02.xml │ ├── test_xml_split_expected-10-03.xml │ ├── test_xml_split_expected-2-01.xml │ ├── test_xml_split_expected-2-02.xml │ ├── test_xml_split_expected-2-03.xml │ ├── test_xml_split_expected-3-01.xml │ ├── test_xml_split_expected-3-02.xml │ ├── test_xml_split_expected-3-03.xml │ ├── test_xml_split_expected-3-04.xml │ ├── test_xml_split_expected-3-05.xml │ ├── test_xml_split_expected-3-06.xml │ ├── test_xml_split_expected-3-07.xml │ ├── test_xml_split_expected-3-08.xml │ ├── test_xml_split_expected-3-09.xml │ ├── test_xml_split_expected-4-01.xml │ ├── test_xml_split_expected-4-02.xml │ ├── test_xml_split_expected-4-03.xml │ ├── test_xml_split_expected-4-04.xml │ ├── test_xml_split_expected-4-05.xml │ ├── test_xml_split_expected-4-06.xml │ ├── test_xml_split_expected-4-07.xml │ ├── test_xml_split_expected-4-08.xml │ ├── test_xml_split_expected-4-09.xml │ ├── test_xml_split_expected-9-01.xml │ ├── test_xml_split_expected-9-02.xml │ ├── test_xml_split_expected-9-03.xml │ ├── test_xml_split_expected-13-01.xml │ ├── test_xml_split_expected-13-02.xml │ ├── test_xml_split_expected-14-02.xml │ ├── test_xml_split_expected-15-01.xml │ ├── test_xml_split_expected-15-02.xml │ ├── test_xml_split_expected-16-01.xml │ ├── test_xml_split_expected-16-02.xml │ ├── test_xml_split_expected-16-03.xml │ ├── test_xml_split_expected-17-01.xml │ ├── test_xml_split_expected-17-02.xml │ ├── test_xml_split_expected-17-03.xml │ ├── test_xml_split_expected-17-04.xml │ ├── test_xml_split_expected-17-05.xml │ ├── test_xml_split_expected-17-06.xml │ ├── test_xml_split_expected-17-07.xml │ ├── test_xml_split_expected-17-08.xml │ ├── test_xml_split_expected-17-09.xml │ ├── test_xml_split_expected-19-01.xml │ ├── test_xml_split_expected-19-02.xml │ ├── test_xml_split_expected-19-03.xml │ ├── test_xml_split_expected-7-02.xml │ ├── test_xml_split_expected-8-02.xml │ ├── test_xml_split_expected-7-00.xml │ ├── test_xml_split_expected-8-00.xml │ ├── test_xml_split_expected-1-04.xml │ ├── test_xml_split_expected-10-04.xml │ ├── test_xml_split_expected-11-00.xml │ ├── test_xml_split_expected-12-00.xml │ ├── test_xml_split_expected-2-04.xml │ ├── test_xml_split_expected-5-01.xml │ ├── test_xml_split_expected-6-01.xml │ ├── test_xml_split_expected-9-04.xml │ ├── test_xml_split_expected-14-00.xml │ ├── test_xml_split_expected-5-02.xml │ ├── test_xml_split_expected-6-02.xml │ ├── test_xml_split_expected-20-00.xml │ ├── test_xml_split_expected-16-04.xml │ ├── test_xml_split_expected-19-04.xml │ ├── test_xml_split_expected-21-03.xml │ ├── test_xml_split_expected-6-03.xml │ ├── test_xml_split_expected-13-00.xml │ ├── test_xml_split_expected-15-00.xml │ ├── test_xml_split_expected-5-03.xml │ ├── test_xml_split_expected-18-01.xml │ ├── test_xml_split_expected-21-01.xml │ ├── test_xml_split_expected-1-05.xml │ ├── test_xml_split_expected-14-01.xml │ ├── test_xml_split_expected-2-05.xml │ ├── test_xml_split_expected-9-05.xml │ ├── test_xml_split_expected-10-05.xml │ ├── test_xml_split_expected-16-05.xml │ ├── test_xml_split_expected-19-05.xml │ ├── test_xml_split_expected-18-02.xml │ ├── test_xml_split_expected-18-00.xml │ ├── test_xml_split_expected-21-02.xml │ ├── test_xml_split_expected-5-00.xml │ ├── test_xml_split_expected-6-00.xml │ ├── test_xml_split_expected-18-03.xml │ ├── test_xml_split_expected-2-00.xml │ ├── test_xml_split_expected-1-00.xml │ ├── test_xml_split_expected-10-00.xml │ ├── test_xml_split_expected-9-00.xml │ ├── test_xml_split_expected-16-00.xml │ ├── test_xml_split_expected-19-00.xml │ ├── test_xml_split_expected-21-00.xml │ ├── test_xml_split_expected-11-01.xml │ ├── test_xml_split_expected-12-01.xml │ ├── test_xml_split_expected-7-01.xml │ ├── test_xml_split_expected-8-01.xml │ ├── test_xml_split_expected-20-01.xml │ ├── test_xml_split_expected-4-00.xml │ ├── test_xml_split_expected-3-00.xml │ └── test_xml_split_expected-17-00.xml ├── latin1_accented_char.iso-8859-1 ├── test_new_features_3_22.html ├── test_expand_external_entities.xml ├── test_expand_external_entities.dtd ├── test_xml_split_entities.xml ├── test_meta_json.t ├── test_changes.t ├── dummy.dtd ├── test_3_48.t ├── pod.t ├── test_xml_split.xml ├── pod_coverage.t ├── test_xml_split_w_decl.xml ├── xmlxpath_tools.pm ├── test2_2.dtd ├── test_kwalitee.t ├── test_even_more_coverage.t ├── xmlxpath_04pos.t ├── xmlxpath_02descendant.t ├── xmlxpath_22name_select.t ├── xmlxpath_13axisparent.t ├── xmlxpath_25scope.t ├── xmlxpath_29desc_with_predicate.t ├── xmlxpath_30lang.t ├── xmlxpath_26predicate.t ├── xmlxpath_19axisd_or_s.t ├── xmlxpath_20axisa_or_s.t ├── xmlxpath_06attrib_val.t ├── test_new_features_3_15.t ├── xmlxpath_03star.t ├── xmlxpath_05attrib.t ├── test_error_with_unicode_layer ├── xmlxpath_01basic.t ├── xmlxpath_14axisancestor.t ├── xmlxpath_08name.t ├── xmlxpath_09string_length.t ├── xmlxpath_10pipe.t ├── xmlxpath_15axisfol_sib.t ├── xmlxpath_07count.t ├── xmlxpath_12axisdescendant.t ├── xmlxpath_09a_string_length.t ├── test2_3.res ├── xmlxpath_18axispreceding.t ├── xmlxpath_17axisfollowing.t ├── test_3_32.t ├── xmlxpath_23func.t ├── test_3_42.t ├── test2_2.xml ├── xmlxpath_16axisprec_sib.t ├── test_drop_comments.t ├── tests_3_23.t ├── test2_2.res ├── test2_1.res ├── test2_1.exp ├── test2_2.exp ├── test_autoencoding_conversion.t ├── xmlxpath_28ancestor2.t ├── test_need_3_args_open.t ├── test_spaces.t ├── test_3_47.t ├── test2_1.xml ├── test_variables.t ├── xmlxpath_nav.t ├── test_attregexp_cond.t ├── xmlxpath_21allnodes.t ├── test_expand_external_entities.t ├── is_field.t ├── test_pos.t ├── test_class_selector.t ├── test_need_use_bytes.t ├── test_cdata.t ├── test_safe_encode.t ├── test_pi_handler.t ├── xmlxpath_test_with_handlers.t ├── test_3_55.t ├── test_comment_handler.t ├── test_erase.t ├── test_unique_xpath.t ├── test_class_methods.t ├── test_xml_split_g.t ├── test_mark.t ├── test2.t ├── test_keep_atts_order.t ├── test_3_35.t ├── test_with_lwp.t ├── test_ignore_elts.t ├── test_3_39.t ├── xmlxpath_xpath_cond.t ├── test_wrapped.t ├── test_xpath_cond.t ├── test_3_24.t ├── test_3_45.t ├── zz_dump_config.t ├── test_3_50.t ├── test_3_38.t ├── test3.t ├── xmlxpath_31vars.t ├── test_bugs_3_21.t ├── test_bugs_3_19.t └── test_memory.t ├── Changes ├── doc_utf8.xml ├── doc_latin1.xml ├── tmp_file ├── list_deps ├── filter_for_5.005 ├── html2xml ├── cover_twig ├── check_optional_modules ├── upd_changes ├── parse_random_files ├── README ├── speedup.pl └── tools └── xml_merge └── xml_merge /test_uri: -------------------------------------------------------------------------------- 1 | ok -------------------------------------------------------------------------------- /t/test_new_features_3_22.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirod/xmltwig/HEAD/Changes -------------------------------------------------------------------------------- /t/test_with_lwp.xml: -------------------------------------------------------------------------------- 1 | 2 | text 3 | 4 | -------------------------------------------------------------------------------- /t/test4.t: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirod/xmltwig/HEAD/t/test4.t -------------------------------------------------------------------------------- /t/test_with_lwp_not_wf.xml: -------------------------------------------------------------------------------- 1 | 2 | text 3 | 4 | -------------------------------------------------------------------------------- /doc_utf8.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirod/xmltwig/HEAD/doc_utf8.xml -------------------------------------------------------------------------------- /doc_latin1.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirod/xmltwig/HEAD/doc_latin1.xml -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-1-01.xml: -------------------------------------------------------------------------------- 1 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-1-02.xml: -------------------------------------------------------------------------------- 1 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-1-03.xml: -------------------------------------------------------------------------------- 1 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-10-01.xml: -------------------------------------------------------------------------------- 1 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-10-02.xml: -------------------------------------------------------------------------------- 1 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-10-03.xml: -------------------------------------------------------------------------------- 1 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-2-01.xml: -------------------------------------------------------------------------------- 1 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-2-02.xml: -------------------------------------------------------------------------------- 1 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-2-03.xml: -------------------------------------------------------------------------------- 1 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-01.xml: -------------------------------------------------------------------------------- 1 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-02.xml: -------------------------------------------------------------------------------- 1 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-03.xml: -------------------------------------------------------------------------------- 1 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-04.xml: -------------------------------------------------------------------------------- 1 | elt1 content 4 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-05.xml: -------------------------------------------------------------------------------- 1 | elt1 content 5 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-06.xml: -------------------------------------------------------------------------------- 1 | elt1 content 6 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-07.xml: -------------------------------------------------------------------------------- 1 | elt1 content 7 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-08.xml: -------------------------------------------------------------------------------- 1 | elt1 content 8 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-09.xml: -------------------------------------------------------------------------------- 1 | elt1 content 9 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-01.xml: -------------------------------------------------------------------------------- 1 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-02.xml: -------------------------------------------------------------------------------- 1 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-03.xml: -------------------------------------------------------------------------------- 1 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-04.xml: -------------------------------------------------------------------------------- 1 | elt1 content 4 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-05.xml: -------------------------------------------------------------------------------- 1 | elt1 content 5 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-06.xml: -------------------------------------------------------------------------------- 1 | elt1 content 6 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-07.xml: -------------------------------------------------------------------------------- 1 | elt1 content 7 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-08.xml: -------------------------------------------------------------------------------- 1 | elt1 content 8 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-09.xml: -------------------------------------------------------------------------------- 1 | elt1 content 9 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-9-01.xml: -------------------------------------------------------------------------------- 1 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-9-02.xml: -------------------------------------------------------------------------------- 1 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-9-03.xml: -------------------------------------------------------------------------------- 1 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-13-01.xml: -------------------------------------------------------------------------------- 1 | text with < > & and ' -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-13-02.xml: -------------------------------------------------------------------------------- 1 | & and ']]> -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-14-02.xml: -------------------------------------------------------------------------------- 1 | & and ']]> -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-15-01.xml: -------------------------------------------------------------------------------- 1 | text with < > & and ' -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-15-02.xml: -------------------------------------------------------------------------------- 1 | & and ']]> -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-16-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-16-02.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-16-03.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-02.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-03.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-04.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 4 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-05.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 5 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-06.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 6 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-07.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 7 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-08.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 8 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-09.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 9 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-19-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-19-02.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 2 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-19-03.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 3 -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-7-02.xml: -------------------------------------------------------------------------------- 1 | & and ']]> 2 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-8-02.xml: -------------------------------------------------------------------------------- 1 | & and ']]> 2 | -------------------------------------------------------------------------------- /t/latin1_accented_char.iso-8859-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirod/xmltwig/HEAD/t/latin1_accented_char.iso-8859-1 -------------------------------------------------------------------------------- /t/test_new_features_3_22.html: -------------------------------------------------------------------------------- 1 | Tt
t2

t3 -------------------------------------------------------------------------------- /tmp_file: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | fi4 7 | 8 | 9 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-7-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-8-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-1-04.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 4 3 | elt1 content 5 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-10-04.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 4 3 | elt1 content 5 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-11-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-12-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-2-04.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 4 3 | elt1 content 5 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-5-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 4 3 | elt1 content 5 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-6-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 4 3 | elt1 content 5 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-9-04.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 4 3 | elt1 content 5 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-14-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-5-02.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 6 3 | elt1 content 7 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-6-02.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 6 3 | elt1 content 7 4 | -------------------------------------------------------------------------------- /list_deps: -------------------------------------------------------------------------------- 1 | perl -MCPAN::ReverseDependencies -E'$,="\n"; $r= CPAN::ReverseDependencies->new; my @l= $r->get_reverse_dependencies( "XML-Twig"); say @l' 2 | -------------------------------------------------------------------------------- /t/test_expand_external_entities.xml: -------------------------------------------------------------------------------- 1 | 2 |

&ent1;

&ent2;

more &ent1;

3 | -------------------------------------------------------------------------------- /t/test_expand_external_entities.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ent2 text

"> 5 | 6 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-20-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /t/test_xml_split_entities.xml: -------------------------------------------------------------------------------- 1 | 2 | text with < > & and ' 3 | & and ']]> 4 | 5 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-16-04.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 4 4 | elt1 content 5 5 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-19-04.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 4 4 | elt1 content 5 5 | -------------------------------------------------------------------------------- /t/test_meta_json.t: -------------------------------------------------------------------------------- 1 | use Test::More; 2 | eval "use Test::CPAN::Meta::JSON"; 3 | plan skip_all => "Test::CPAN::Meta::JSON required for testing META.json" if $@; 4 | meta_json_ok(); 5 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-21-03.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 9 4 | 5 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-6-03.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 8 4 | elt1 content 9 5 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-13-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-15-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-5-03.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 8 4 | elt1 content 9 5 | -------------------------------------------------------------------------------- /filter_for_5.005: -------------------------------------------------------------------------------- 1 | # $Id: /xmltwig/trunk/filter_for_5.005 4 2007-03-16T12:16:25.259192Z mrodrigu $ 2 | if( $] < 5.006) { s{^(\s*)no warnings;}{$1# no warnings;}; } 3 | else { s{^(\s*)# no warnings; }{$1no warnings;}; } 4 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-18-01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 1 4 | elt1 content 2 5 | 6 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-21-01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 4 4 | elt1 content 5 5 | 6 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-1-05.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 6 4 | elt1 content 7 5 | 6 | elt1 content 8 7 | elt1 content 9 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-14-01.xml: -------------------------------------------------------------------------------- 1 | 2 | text with < > & and ' 3 | & and ']]> 4 | 5 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-2-05.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 6 4 | elt1 content 7 5 | 6 | elt1 content 8 7 | elt1 content 9 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-9-05.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 6 4 | elt1 content 7 5 | 6 | elt1 content 8 7 | elt1 content 9 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-10-05.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 6 4 | elt1 content 7 5 | 6 | elt1 content 8 7 | elt1 content 9 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-16-05.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | elt1 content 6 5 | elt1 content 7 6 | 7 | elt1 content 8 8 | elt1 content 9 9 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-19-05.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | elt1 content 6 5 | elt1 content 7 6 | 7 | elt1 content 8 8 | elt1 content 9 9 | -------------------------------------------------------------------------------- /t/test_changes.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use Test::More; 4 | eval 'use Test::CPAN::Changes'; 5 | plan skip_all => 'Test::CPAN::Changes required for this test' if $@; 6 | plan skip_all => 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.' if ! $ENV{TEST_AUTHOR}; 7 | changes_ok(); 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-18-02.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 3 4 | 5 | elt1 content 4 6 | elt1 content 5 7 | 8 | 9 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-18-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-21-02.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | elt1 content 6 5 | elt1 content 7 6 | 7 | elt1 content 8 8 | 9 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-5-00.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 3 | elt1 content 2 4 | elt1 content 3 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-6-00.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 3 | elt1 content 2 4 | elt1 content 3 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /t/dummy.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /t/test_3_48.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use XML::Twig; 7 | use Test::More tests => 1; 8 | 9 | use utf8; 10 | 11 | { 12 | XML::Twig::_disallow_use( 'Tie::IxHash'); 13 | my $t; 14 | eval { $t= XML::Twig->new( keep_atts_order => 0); }; 15 | ok( $t, 'keep_atts_order => 0'); 16 | } 17 | 18 | 19 | exit; 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-18-03.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | elt1 content 6 6 | elt1 content 7 7 | 8 | elt1 content 8 9 | elt1 content 9 10 | 11 | 12 | -------------------------------------------------------------------------------- /t/pod.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | 5 | if( ! $ENV{TEST_AUTHOR} ) { print "1..1\nok 1\n"; warn "Author test. Set \$ENV{TEST_AUTHOR} to a true value to run.\n"; exit; } 6 | 7 | eval "use Test::Pod 1.00"; 8 | if( $@) { print "1..1\nok 1\n"; warn "skipping, Test::Pod required\n"; } 9 | else { all_pod_files_ok( ); } 10 | 11 | 12 | exit 0; 13 | 14 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-2-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-1-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-10-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-9-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-16-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-19-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /t/test_xml_split.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 3 | elt1 content 2 4 | elt1 content 3 5 | 6 | elt1 content 4 7 | elt1 content 5 8 | 9 | 10 | 11 | elt1 content 6 12 | elt1 content 7 13 | 14 | elt1 content 8 15 | elt1 content 9 16 | 17 | 18 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-21-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 1 4 | elt1 content 2 5 | elt1 content 3 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /t/pod_coverage.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | 5 | if( ! $ENV{TEST_AUTHOR} ) { print "1..1\nok 1\n"; warn "Author test. Set \$ENV{TEST_AUTHOR} to a true value to run.\n"; exit; } 6 | 7 | eval "use Test::Pod::Coverage 1.00 tests => 1"; 8 | if( $@) 9 | { print "1..1\nok 1\n"; 10 | warn "Test::Pod::Coverage 1.00 required for testing POD coverage"; 11 | exit; 12 | } 13 | 14 | pod_coverage_ok( "XML::Twig", { trustme => [ 'isa' ] }); 15 | -------------------------------------------------------------------------------- /t/test_xml_split_w_decl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 1 4 | elt1 content 2 5 | elt1 content 3 6 | 7 | elt1 content 4 8 | elt1 content 5 9 | 10 | 11 | 12 | elt1 content 6 13 | elt1 content 7 14 | 15 | elt1 content 8 16 | elt1 content 9 17 | 18 | 19 | -------------------------------------------------------------------------------- /t/xmlxpath_tools.pm: -------------------------------------------------------------------------------- 1 | use strict; 2 | use Config; 3 | 4 | BEGIN 5 | { if( eval( 'require XML::Twig::XPath')) 6 | { import XML::Twig::XPath; } 7 | elsif( $@ =~ m{^cannot use XML::Twig::XPath}) 8 | { print "1..1\nok 1\n"; $@=~s{ at.*}{}s; warn "$@\n"; 9 | exit; 10 | } 11 | else 12 | { die $@; } 13 | } 14 | 15 | 1; 16 | 17 | __END__ 18 | 19 | =head1 SYNOPSYS 20 | 21 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 22 | 23 | -------------------------------------------------------------------------------- /t/test2_2.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /t/test_kwalitee.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | 5 | if( ! $ENV{TEST_AUTHOR} ) { print "1..1\nok 1\n"; warn "Author test. Set \$ENV{TEST_AUTHOR} to a true value to run.\n"; exit; } 6 | 7 | eval { require Test::More; Test::More->import(); }; 8 | if( $@) { print "1..1\nok 1\n"; warn "need test::More installed for this test\n"; exit; } 9 | 10 | eval { require Test::Kwalitee; Test::Kwalitee->import() }; 11 | plan( skip_all => 'Test::Kwalitee not installed; skipping' ) if $@; 12 | 13 | 14 | -------------------------------------------------------------------------------- /t/test_even_more_coverage.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | 4 | # test designed to improve coverage of the module 5 | 6 | use strict; 7 | use Carp; 8 | 9 | use File::Spec; 10 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 11 | use tools; 12 | 13 | #$|=1; 14 | my $DEBUG=0; 15 | 16 | use XML::Twig; 17 | 18 | my $TMAX=1; 19 | 20 | print "1..$TMAX\n"; 21 | 22 | { my $t= XML::Twig->new( parse_start_tag => sub { return 'a'; })->parse( 'c'); 23 | is( $t->sprint, 'c', "dummy parse_start_tag"); 24 | } 25 | exit 0; 26 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-11-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 3 | elt1 content 2 4 | elt1 content 3 5 | 6 | elt1 content 4 7 | elt1 content 5 8 | 9 | 10 | 11 | elt1 content 6 12 | elt1 content 7 13 | 14 | elt1 content 8 15 | elt1 content 9 16 | 17 | 18 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-12-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 3 | elt1 content 2 4 | elt1 content 3 5 | 6 | elt1 content 4 7 | elt1 content 5 8 | 9 | 10 | 11 | elt1 content 6 12 | elt1 content 7 13 | 14 | elt1 content 8 15 | elt1 content 9 16 | 17 | 18 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-7-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 3 | elt1 content 2 4 | elt1 content 3 5 | 6 | elt1 content 4 7 | elt1 content 5 8 | 9 | 10 | 11 | elt1 content 6 12 | elt1 content 7 13 | 14 | elt1 content 8 15 | elt1 content 9 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-8-01.xml: -------------------------------------------------------------------------------- 1 | 2 | elt1 content 1 3 | elt1 content 2 4 | elt1 content 3 5 | 6 | elt1 content 4 7 | elt1 content 5 8 | 9 | 10 | 11 | elt1 content 6 12 | elt1 content 7 13 | 14 | elt1 content 8 15 | elt1 content 9 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /t/xmlxpath_04pos.t: -------------------------------------------------------------------------------- 1 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 2 | use Test; 3 | plan( tests => 4); 4 | 5 | 6 | use XML::Twig::XPath; 7 | ok(1); 8 | 9 | my $t= XML::Twig::XPath->new->parse( \*DATA); 10 | 11 | ok( $t); 12 | 13 | my $first = $t->findvalue( '/AAA/BBB[1]/@id'); 14 | ok($first, "first"); 15 | 16 | my $last = $t->findvalue( '/AAA/BBB[last()]/@id'); 17 | ok($last, "last"); 18 | 19 | exit 0; 20 | 21 | __DATA__ 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /t/xmlxpath_02descendant.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 5 | 6 | use Test; 7 | plan( tests => 4); 8 | 9 | ok(1); 10 | 11 | my $t= XML::Twig::XPath->new->parse( \*DATA); 12 | ok($t); 13 | 14 | my @bbb = $t->findnodes('//BBB'); 15 | ok(@bbb, 5); 16 | 17 | my @subbbb = $t->findnodes('//DDD/BBB'); 18 | ok(@subbbb, 3); 19 | 20 | exit 0; 21 | 22 | __DATA__ 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-20-01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | elt1 content 1 4 | elt1 content 2 5 | elt1 content 3 6 | 7 | elt1 content 4 8 | elt1 content 5 9 | 10 | 11 | 12 | elt1 content 6 13 | elt1 content 7 14 | 15 | elt1 content 8 16 | elt1 content 9 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /t/xmlxpath_22name_select.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//*[name() = /AAA/SELECT]'); 20 | ok(@nodes, 2); 21 | ok($nodes[0]->getName, "BBB"); 22 | 23 | exit 0; 24 | 25 | __DATA__ 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /t/xmlxpath_13axisparent.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//DDD/parent::*'); 20 | ok(@nodes, 4); 21 | ok($nodes[3]->getName, "EEE"); 22 | 23 | exit 0; 24 | 25 | __DATA__ 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /t/xmlxpath_25scope.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | 6 | use strict; 7 | 8 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 9 | 10 | use Test; 11 | plan( tests => 4); 12 | 13 | 14 | use XML::Twig::XPath; 15 | ok(1); 16 | 17 | eval 18 | { 19 | # Removing the 'my' makes this work?!? 20 | my $t= XML::Twig::XPath->new->parse( ''); 21 | ok( $t); 22 | 23 | $t->findnodes( '/test'); 24 | 25 | ok(1); 26 | 27 | die "This should be caught\n"; 28 | 29 | }; 30 | 31 | if ($@) 32 | { 33 | ok(1); 34 | } 35 | else { 36 | ok(0); 37 | } 38 | 39 | exit 0; 40 | -------------------------------------------------------------------------------- /t/xmlxpath_29desc_with_predicate.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @bbb = $t->findnodes( '/descendant::BBB[1]'); 19 | ok(@bbb, 1); 20 | ok($bbb[0]->string_value, "OK"); 21 | 22 | exit 0; 23 | 24 | __DATA__ 25 | 26 | OK 27 | 28 | 29 | 30 | NOT OK 31 | 32 | -------------------------------------------------------------------------------- /t/xmlxpath_30lang.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new( keep_spaces => 1)->parse( \*DATA); 15 | ok( $t); 16 | 17 | my @en = $t->findnodes( '//*[lang("en")]'); 18 | ok(@en, 2); 19 | 20 | my @de = $t->findnodes( '//content[lang("de")]'); 21 | ok(@de, 1); 22 | 23 | exit 0; 24 | 25 | __DATA__ 26 | 27 | Here we go... 28 | und hier deutschsprachiger Text :-) 29 | 30 | -------------------------------------------------------------------------------- /t/xmlxpath_26predicate.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @bbb = $t->findnodes( '//a/b[2]'); 19 | ok(@bbb, 2); 20 | 21 | @bbb = $t->findnodes( '(//a/b)[2]'); 22 | ok(@bbb, 1); 23 | 24 | exit 0; 25 | 26 | __DATA__ 27 | 28 | 29 | some 1 30 | value 1 31 | 32 | 33 | some 2 34 | value 2 35 | 36 | 37 | -------------------------------------------------------------------------------- /t/xmlxpath_19axisd_or_s.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '/AAA/XXX/descendant-or-self::*'); 20 | ok(@nodes, 8); 21 | 22 | @nodes = $t->findnodes( '//CCC/descendant-or-self::*'); 23 | ok(@nodes, 4); 24 | 25 | exit 0; 26 | 27 | __DATA__ 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /t/xmlxpath_20axisa_or_s.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '/AAA/XXX/DDD/EEE/ancestor-or-self::*'); 20 | ok(@nodes, 4); 21 | 22 | @nodes = $t->findnodes( '//GGG/ancestor-or-self::*'); 23 | ok(@nodes, 5); 24 | 25 | exit 0; 26 | 27 | __DATA__ 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /t/xmlxpath_06attrib_val.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 5); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//BBB[@id = "b1"]'); 20 | ok(@nodes, 1); 21 | 22 | @nodes = $t->findnodes( '//BBB[@name = "bbb"]'); 23 | ok(@nodes, 1); 24 | 25 | @nodes = $t->findnodes( '//BBB[normalize-space(@name) = "bbb"]'); 26 | ok(@nodes, 2); 27 | 28 | exit 0; 29 | 30 | __DATA__ 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /t/test_new_features_3_15.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | # test designed to improve coverage of the module 6 | 7 | use strict; 8 | use Carp; 9 | 10 | use File::Spec; 11 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 12 | use tools; 13 | 14 | #$|=1; 15 | my $DEBUG=0; 16 | 17 | use XML::Twig; 18 | 19 | my $TMAX=1; 20 | print "1..$TMAX\n"; 21 | 22 | { my $indented="\n \n\n"; 23 | (my $straight=$indented)=~ s{\s}{}g; 24 | is( XML::Twig->new( pretty_print => 'indented')->parse( $indented)->sprint, 25 | $indented, "pretty printed doc"); exit; 26 | is( XML::Twig->new()->parse( $indented)->sprint, 27 | $straight, "non pretty printed doc"); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /t/xmlxpath_03star.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 4 | 5 | use Test; 6 | plan( tests => 5); 7 | 8 | 9 | use XML::Twig::XPath; 10 | ok(1); 11 | 12 | my $t= XML::Twig::XPath->new->parse( \*DATA); 13 | 14 | ok( $t); 15 | 16 | my @nodes; 17 | 18 | @nodes = $t->findnodes( '/AAA/CCC/DDD/*'); 19 | ok(@nodes, 4); 20 | 21 | @nodes = $t->findnodes( '/*/*/*/BBB'); 22 | ok(@nodes, 5); 23 | 24 | @nodes = $t->findnodes( '//*'); 25 | ok(@nodes, 17); 26 | 27 | exit 0; 28 | 29 | __DATA__ 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /t/xmlxpath_05attrib.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use Test; 4 | plan( tests => 6); 5 | 6 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 7 | 8 | use XML::Twig::XPath; 9 | ok(1); 10 | 11 | my $t= XML::Twig::XPath->new->parse( \*DATA); 12 | 13 | ok( $t); 14 | 15 | my @ids = $t->findnodes( '//BBB[@id]'); 16 | ok(@ids, 2); 17 | 18 | my @names = $t->findnodes( '//BBB[@name]'); 19 | ok(@names, 1); 20 | 21 | my @attribs = $t->findnodes( '//BBB[@*]'); 22 | ok(@attribs, 3); 23 | 24 | my @noattribs = $t->findnodes( '//BBB[not(@*)]'); 25 | ok(@noattribs, 1); 26 | 27 | exit 0; 28 | 29 | __DATA__ 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /t/test_error_with_unicode_layer: -------------------------------------------------------------------------------- 1 | use XML::Twig; 2 | 3 | use strict; 4 | use Config; 5 | 6 | my( $infile)= @ARGV; 7 | 8 | my $perl= used_perl(); 9 | open( FH, "$perl -p -e1 $infile |") or die $!; 10 | XML::Twig->nparse( \*FH); 11 | die "OK\n"; 12 | 13 | 14 | sub used_perl 15 | { my $perl; 16 | if( $^O eq 'VMS') { $perl= $Config{perlpath}; } # apparently $^X does not work on VMS 17 | else { $perl= $^X; } # but $Config{perlpath} does not work in 5.005 18 | if ($^O ne 'VMS' && $Config{_exe} && $perl !~ m{$Config{_exe}$}i) { $perl .= $Config{_exe}; } 19 | $perl .= " -Iblib/lib"; 20 | if( $ENV{TEST_COVER}) { $perl .= " -MDevel::Cover"; } 21 | return $perl; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /t/xmlxpath_01basic.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 5 | 6 | use Test; 7 | plan( tests => 5); 8 | 9 | ok(1); 10 | my $t= XML::Twig::XPath->new->parse( \*DATA); 11 | ok($t); 12 | 13 | my @root = $t->findnodes('/AAA'); 14 | ok(@root, 1); 15 | 16 | my @ccc = $t->findnodes('/AAA/CCC'); 17 | ok(@ccc, 3); 18 | 19 | my @bbb = $t->findnodes('/AAA/DDD/BBB'); 20 | ok(@bbb, 2); 21 | 22 | exit 0; 23 | 24 | __DATA__ 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Text 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /t/xmlxpath_14axisancestor.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 5); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '/AAA/BBB/DDD/CCC/EEE/ancestor::*'); 20 | ok(@nodes, 4); 21 | ok($nodes[1]->getName, "BBB"); # test document order 22 | 23 | @nodes = $t->findnodes( '//FFF/ancestor::*'); 24 | ok(@nodes, 5); 25 | 26 | exit 0; 27 | 28 | __DATA__ 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /t/xmlxpath_08name.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 5); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//*[name() = "BBB"]'); 20 | ok(@nodes, 5); 21 | 22 | @nodes = $t->findnodes( '//*[starts-with(name(), "B")]'); 23 | ok(@nodes, 7); 24 | 25 | @nodes = $t->findnodes( '//*[contains(name(), "C")]'); 26 | ok(@nodes, 3); 27 | 28 | exit 0; 29 | 30 | __DATA__ 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /t/xmlxpath_09string_length.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 5); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//*[string-length(name()) = 3]'); 20 | ok(@nodes, 2); 21 | 22 | @nodes = $t->findnodes( '//*[string-length(name()) < 3]'); 23 | ok(@nodes, 2); 24 | 25 | @nodes = $t->findnodes( '//*[string-length(name()) > 3]'); 26 | ok(@nodes, 3); 27 | 28 | exit 0; 29 | 30 | __DATA__ 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /t/xmlxpath_10pipe.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 6); 9 | 10 | use XML::Twig::XPath; 11 | ok(1); 12 | 13 | my $t= XML::Twig::XPath->new->parse( \*DATA); 14 | 15 | ok( $t); 16 | 17 | my @nodes; 18 | @nodes = $t->findnodes( '//CCC | //BBB'); 19 | ok(@nodes, 3); 20 | ok($nodes[0]->getName, "BBB"); # test document order 21 | 22 | @nodes = $t->findnodes( '/AAA/EEE | //BBB'); 23 | ok(@nodes, 2); 24 | 25 | @nodes = $t->findnodes( '/AAA/EEE | //DDD/CCC | /AAA | //BBB'); 26 | ok(@nodes, 4); 27 | 28 | exit 0; 29 | 30 | __DATA__ 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-4-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /t/xmlxpath_15axisfol_sib.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 6); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '/AAA/BBB/following-sibling::*'); 20 | ok(@nodes, 2); 21 | ok($nodes[1]->getName, "CCC"); # test document order 22 | 23 | @nodes = $t->findnodes( '//CCC/following-sibling::*'); 24 | ok(@nodes, 3); 25 | ok($nodes[1]->getName, "FFF"); 26 | 27 | exit 0; 28 | 29 | __DATA__ 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /t/xmlxpath_07count.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 7); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//*[count(BBB) = 2]'); 20 | ok($nodes[0]->getName, "DDD"); 21 | 22 | @nodes = $t->findnodes( '//*[count(*) = 2]'); 23 | ok(@nodes, 2); 24 | 25 | @nodes = $t->findnodes( '//*[count(*) = 3]'); 26 | ok(@nodes, 2); 27 | ok($nodes[0]->getName, "AAA"); 28 | ok($nodes[1]->getName, "CCC"); 29 | 30 | exit 0; 31 | 32 | __DATA__ 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-3-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /html2xml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use warnings; 3 | use strict; 4 | 5 | use XML::Twig; 6 | 7 | sub _chose_html_string 8 | { if( _use( 'XML::LibXML')) 9 | { $html2xml 10 | 11 | sub parsefile_html 12 | { my( $twig, $file)= @_; 13 | my $fh; 14 | 15 | open( $fh, "tidy -asxml -quiet 2>/dev/null '$file' |") 16 | or open( $fh, "xmllint -html '$file' |") 17 | or open( $fh, "$^X -MXML::LibXML -e'print XML::LibXML->new->parse_html_file( \'$file\')->toString' |") 18 | or carp "cannot convert HTML to XML (needs tidy, xmllint or XML::LibXML)"; 19 | $twig->parse( $fh); 20 | } 21 | 22 | 23 | sub _use 24 | { my( $module, @args)= @_; 25 | if( eval "require $module") { import $module, @args; } 26 | else { return; } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /t/xmlxpath_12axisdescendant.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 6); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '/descendant::*'); 20 | ok(@nodes, 11); 21 | 22 | @nodes = $t->findnodes( '/AAA/BBB/descendant::*'); 23 | ok(@nodes, 4); 24 | 25 | @nodes = $t->findnodes( '//CCC/descendant::*'); 26 | ok(@nodes, 6); 27 | 28 | @nodes = $t->findnodes( '//CCC/descendant::DDD'); 29 | ok(@nodes, 3); 30 | 31 | exit 0; 32 | 33 | __DATA__ 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /t/test_xml_split/test_xml_split_expected-17-00.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /t/xmlxpath_09a_string_length.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 5); 9 | 10 | 11 | use XML::Twig::XPath; 12 | 13 | my $doc_one = qq|para one|; 14 | 15 | my $t= XML::Twig::XPath->new( keep_spaces => 1); 16 | $t->parse( $doc_one); 17 | ok( $t); 18 | 19 | my $doc_one_chars = $t->find( 'string-length(/doc/text())'); 20 | ok($doc_one_chars == 0, 1); 21 | 22 | my $doc_two = qq| 23 | 24 | para one has bold text 25 | 26 | |; 27 | 28 | $t->parse( $doc_two); 29 | ok( $t); 30 | 31 | my $doc_two_chars = $t->find( 'string-length(/doc/text())'); 32 | ok($doc_two_chars == 3, 1); 33 | 34 | my $doc_two_para_chars = $t->find( 'string-length(/doc/para/text())'); 35 | ok($doc_two_para_chars == 13, 1); 36 | 37 | exit 0; 38 | 39 | -------------------------------------------------------------------------------- /t/test2_3.res: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | ]> 6 |
S1 I1S1 I2S1 TitleS1 P1S2 P2Note P1S1 para 3
S2 introS2 TitleS2 P1S2 P2S2 P3
Annex TitleAnnex P1Annex P2
-------------------------------------------------------------------------------- /t/xmlxpath_18axispreceding.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '/AAA/XXX/preceding::*'); 20 | ok(@nodes, 4); 21 | 22 | @nodes = $t->findnodes( '//GGG/preceding::*'); 23 | ok(@nodes, 8); 24 | 25 | exit 0; 26 | 27 | __DATA__ 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /t/xmlxpath_17axisfollowing.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 4); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '/AAA/XXX/following::*'); 20 | ok(@nodes, 2); 21 | 22 | @nodes = $t->findnodes( '//ZZZ/following::*'); 23 | ok(@nodes, 12); 24 | 25 | exit 0; 26 | 27 | __DATA__ 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /t/test_3_32.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use strict; 5 | use Carp; 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | 10 | $|=1; 11 | my $DEBUG=0; 12 | 13 | use XML::Twig; 14 | 15 | my $TMAX=1; 16 | print "1..$TMAX\n"; 17 | 18 | if( $] >= 5.008) 19 | { # test non ascii letters at the beginning of an element name in a selector 20 | # can't use non ascii chars in script, so the tag name needs to come from the doc! 21 | my $doc=q{étésummerestate}; 22 | my $t= XML::Twig->parse( $doc); 23 | my $tag= $t->root->first_child( 'tag')->text; 24 | foreach ($t->root->children( 'elt')) { $_->set_tag( $tag); } 25 | is( $t->root->first_child( $tag)->text, 'summer', 'non ascii letter to start a name in a condition'); 26 | } 27 | else 28 | { skip( 1, "known bug in perl $]: tags starting with a non ascii letter cannot be used in expressions"); } 29 | 30 | exit; 31 | 1; 32 | -------------------------------------------------------------------------------- /cover_twig: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | 5 | use Getopt::Std; 6 | my %opt; 7 | getopts( 'ivrh', \%opt); 8 | 9 | my $run=< cover_report.txt 13 | RUN 14 | 15 | if( ! $opt{i} && ! @ARGV) 16 | { system "cover -delete; $run"; exit; } 17 | 18 | if( @ARGV) 19 | { foreach my $test (@ARGV) 20 | { system "TEST_AUTHOR=1 TEST_COVER=1 $^X -MDevel::Cover $test"; } 21 | } 22 | else 23 | { system "TEST_AUTHOR=1 TEST_COVER=1 HARNESS_PERL_SWITCHES=-MDevel::Cover make test"; } 24 | 25 | system "cover && cover -report text > cover_report.txt"; 26 | 27 | __END__ 28 | =head1 NAME 29 | 30 | cover_twig -- generates test coverage for XML::Twig 31 | 32 | =head1 OPTIONS 33 | 34 | -r reset (delete) the coverage DB ¡DEFAULT! 35 | -i incremental: do not delete the coverage db 36 | 37 | =head1 EXAMPLES 38 | 39 | ./cover_twig 40 | ./cover_twig -r 41 | ./cover_twig t/test_3_36.t 42 | 43 | -------------------------------------------------------------------------------- /t/xmlxpath_23func.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 5); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//BBB[position() mod 2 = 0 ]'); 20 | ok(@nodes, 4); 21 | 22 | @nodes = $t->findnodes('//BBB 23 | [ position() = floor(last() div 2 + 0.5) 24 | or 25 | position() = ceiling(last() div 2 + 0.5) ]'); 26 | 27 | ok(@nodes, 2); 28 | 29 | @nodes = $t->findnodes('//CCC 30 | [ position() = floor(last() div 2 + 0.5) 31 | or 32 | position() = ceiling(last() div 2 + 0.5) ]'); 33 | 34 | ok(@nodes, 1); 35 | 36 | exit 0; 37 | 38 | __DATA__ 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /t/test_3_42.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use XML::Twig; 7 | use Test::More tests => 3; 8 | 9 | 10 | { my $t= XML::Twig->new( twig_handlers => { e => sub { XML::Twig::Elt->parse( '')->paste( before => $_); } }) 11 | ->parse(''); 12 | is( $t->sprint, '', 'elements created with parse are still available once parsing is done'); 13 | } 14 | 15 | import myElt; 16 | 17 | { my $doc='fooe1e2foo'; 18 | my $t= XML::Twig->new( elt_class => 'myElt', 19 | field_accessors => { e => 'e' }, 20 | elt_accessors => { ee => 'e', ef => 'f', }, 21 | ) 22 | ->parse( $doc); 23 | 24 | is( join( ':', map { $_->e } $t->root->ef), 'e1:e2', 'elt_accessors with elt_class'); 25 | is( join( ':', map { $_->ee->text } $t->root->children( 'f')), 'e1:e2', 'field_accessors with elt_class'); 26 | } 27 | 28 | package myElt; 29 | use base 'XML::Twig::Elt'; 30 | 1; 31 | 32 | -------------------------------------------------------------------------------- /check_optional_modules: -------------------------------------------------------------------------------- 1 | #!/bin/perl -w 2 | 3 | # $Id: /xmltwig/trunk/check_optional_modules 4 2007-03-16T12:16:25.259192Z mrodrigu $ 4 | 5 | use strict; 6 | 7 | exit if( $] >= 5.008); 8 | 9 | if( $] >= 5.0060) 10 | { unless( eval 'require Scalar::Util' or eval 'require WeakRef' ) 11 | { warn "Neither Scalar::Util nor WeakRef is installed. ", 12 | "Installing one of these modules would improve ", 13 | "XML::Twig memory management and eliminate memory ", 14 | "leaks when re-using twigs.\n"; 15 | } 16 | else 17 | { warn "weaken is available\n"; } 18 | } 19 | 20 | unless( eval 'require Text::Iconv') 21 | { my $version= `iconv -V` || ''; 22 | if($version) 23 | { warn "The iconv library was found on your system ", 24 | "but the Text::Iconv module is not installed. ", 25 | "Installing Text::Iconv would make character ", 26 | "encoding translations fast and efficient.\n"; 27 | } 28 | else 29 | { warn "Did not find iconv\n"; } 30 | } 31 | else 32 | { warn "Text::Iconv is installed\n"; } 33 | 34 | -------------------------------------------------------------------------------- /t/test2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | ]> 6 | 7 |
8 | 9 | S1 I1 10 | S1 I2 11 | 12 | S1 Title 13 | S1 P1 14 | S2 P2 15 | 16 | Note P1 17 | 18 | S1 para 3 19 |
20 |
21 | 22 | S2 intro 23 | 24 | S2 Title 25 | S2 P1 26 | S2 P2 27 | S2 P3 28 |
29 | 30 | Annex Title 31 | Annex P1 32 | Annex P2 33 | 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /t/xmlxpath_16axisprec_sib.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 7); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '/AAA/XXX/preceding-sibling::*'); 20 | ok(@nodes, 1); 21 | ok($nodes[0]->getName, "BBB"); 22 | 23 | @nodes = $t->findnodes( '//CCC/preceding-sibling::*'); 24 | ok(@nodes, 4); 25 | 26 | @nodes = $t->findnodes( '/AAA/CCC/preceding-sibling::*[1]'); 27 | ok($nodes[0]->getName, "XXX"); 28 | 29 | @nodes = $t->findnodes( '/AAA/CCC/preceding-sibling::*[2]'); 30 | ok($nodes[0]->getName, "BBB"); 31 | 32 | exit 0; 33 | 34 | __DATA__ 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /t/test_drop_comments.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use File::Spec; 5 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 6 | use tools; 7 | 8 | use XML::Twig; 9 | 10 | print "1..3\n"; 11 | 12 | my $xml = < 14 | 15 | value 16 | 17 | XML_TEST 18 | 19 | { 20 | my $twig1 = XML::Twig->new(comments => 'keep', keep_spaces => 1); 21 | $twig1->parse($xml); 22 | ok ($twig1->sprint() =~ //s, 'keep comments'); 23 | #print $twig1->sprint, "\n", '-'x80, "\n"; # keeps comments ok 24 | $twig1->dispose; 25 | } 26 | 27 | { 28 | my $twig2 = XML::Twig->new(comments => 'drop', keep_spaces => 1); 29 | $twig2->parse($xml); 30 | ok ($twig2->sprint() !~ //s, 'drop comments'); 31 | #print $twig2->sprint, "\n", '-'x80, "\n"; # drops comments ok 32 | $twig2->dispose; 33 | } 34 | 35 | { 36 | my $twig3 = XML::Twig->new(comments => 'keep', keep_spaces => 1); 37 | $twig3->parse($xml); 38 | ok ($twig3->sprint() =~ //s, 'keep comments'); 39 | #print $twig3->sprint, "\n", '-'x80, "\n"; # drops comments!! 40 | $twig3->dispose; 41 | } 42 | exit 0; 43 | -------------------------------------------------------------------------------- /t/tests_3_23.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use Carp; 5 | 6 | use XML::Twig; 7 | 8 | use File::Spec; 9 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 10 | use tools; 11 | 12 | my $DEBUG=0; 13 | print "1..6\n"; 14 | 15 | if( _use( 'XML::XPathEngine') || _use( 'XML::XPath') ) 16 | { _use( 'XML::Twig::XPath'); 17 | my $t= XML::Twig::XPath->nparse( q{ 18 | foobar 19 | bazfoobar 20 | }); 21 | is( $t->findvalue( '//e[.="foo"]/@a'), "ea1", 'xpath on attributes'); 22 | is( $t->findvalue( '//s[./e="foo"]/@a'), "sa1", 'xpath with elt content test'); 23 | is( $t->findvalue( '/d/s[e="foo"]/@a'), "sa1", 'xpath with elt content test (short form)'); 24 | } 25 | else 26 | { skip( 3); } 27 | 28 | { my $t= XML::Twig->nparse( ''); 29 | my @xpath_result= $t->get_xpath( '/'); 30 | is( ref( $xpath_result[0]), 'XML::Twig', "get_xpath( '/')"); 31 | @xpath_result= $t->get_xpath( '/doc[1]'); 32 | is( $xpath_result[0]->tag, 'doc', "get_xpath( '/doc[1]')"); 33 | @xpath_result= $t->get_xpath( '/notdoc[1]'); 34 | is( scalar( @xpath_result), 0, "get_xpath( '/notdoc[1]')"); 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /t/test2_2.res: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ]> 17 |
S1 I1S1 I2S1 TitleS1 P1S2 P2Note P1S1 para 3
S2 introS2 TitleS2 P1S2 P2S2 P3
Annex TitleAnnex P1Annex P2
-------------------------------------------------------------------------------- /t/test2_1.res: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ]> 19 |
S1 I1S1 I2S1 TitleS1 P1S2 P2Note P1S1 para 3
S2 introS2 TitleS2 P1S2 P2S2 P3
Annex TitleAnnex P1Annex P2
-------------------------------------------------------------------------------- /t/test2_1.exp: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ]> 20 |
S1 I1S1 I2S1 TitleS1 P1S2 P2Note P1S1 para 3
S2 introS2 TitleS2 P1S2 P2S2 P3
Annex TitleAnnex P1Annex P2
21 | -------------------------------------------------------------------------------- /t/test2_2.exp: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 27 | 28 | ]> 29 |
S1 I1S1 I2S1 TitleS1 P1S2 P2Note P1S1 para 3
S2 introS2 TitleS2 P1S2 P2S2 P3
Annex TitleAnnex P1Annex P2
30 | -------------------------------------------------------------------------------- /t/test_autoencoding_conversion.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | use strict; 4 | 5 | use File::Spec; 6 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 7 | use tools; 8 | 9 | print "1..2\n"; 10 | 11 | if( $] < 5.008) 12 | { skip( 2, "needs perl 5.8 or above to test auto conversion"); } 13 | elsif( $ENV{PERL_UNICODE} && ($ENV{PERL_UNICODE}=~ m{S} && $ENV{PERL_UNICODE}=~ m{A})) 14 | { skip( 2, 'auto conversion does not happen when $PERL_UNICODE set to SA'); } 15 | else 16 | { _use( 'Encode'); 17 | 18 | my $char_utf8 = qq{\x{e9}}; 19 | my $char_latin1 = encode("iso-8859-1", $char_utf8); 20 | my $doc_utf8 = qq{$char_utf8}; 21 | my $doc_latin1 = qq{$char_latin1}; 22 | 23 | my $file_utf8 = "doc_utf8.xml"; 24 | spit( $file_utf8, $doc_utf8); 25 | my $file_latin1 = "doc_latin1.xml"; 26 | spit( $file_latin1, $doc_latin1); 27 | 28 | my( $q, $q2) = ( ($^O eq "MSWin32") || ($^O eq 'VMS') ) ? ('"', "'") : ("'", '"'); 29 | my $lib= File::Spec->catfile( 'blib', 'lib'); 30 | my $run_it=qq{$^X -I $lib -MXML::Twig -e$q print XML::Twig->parse( $q2$file_latin1$q2)->root->text$q}; 31 | my $parsed= `$run_it`; 32 | is( $parsed, $char_utf8, 'testing auto transcoding of latin1 output'); 33 | is( $parsed, $char_latin1, 'testing auto transcoding of latin1 output'); 34 | } 35 | -------------------------------------------------------------------------------- /t/xmlxpath_28ancestor2.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 5); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//Footnote'); 20 | ok(@nodes, 1); 21 | 22 | my $footnote = $nodes[0]; 23 | 24 | #@nodes = $footnote->findnodes('ancestor::*', $t); 25 | @nodes = $footnote->findnodes( 'ancestor::*'); 26 | ok(@nodes, 3); 27 | 28 | @nodes = $footnote->findnodes('ancestor::text:footnote', $t); 29 | ok(@nodes, 1); 30 | 31 | exit 0; 32 | 33 | __DATA__ 34 | 35 | 36 | 2 37 | 38 | AxKit 40 | is very flexible in how it lets you transform the XML on the 41 | server, and there are many modules you can plug in to AxKit to 42 | allow you to do these transformations. For this reason, the AxKit 43 | installation does not mandate any particular modules to use, 44 | instead it will simply suggest modules that might help when you 45 | install AxKit. 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /t/test_need_3_args_open.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use Carp; 5 | 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | 10 | 11 | $|=1; 12 | 13 | use XML::Twig; 14 | 15 | # abort (before compiling so the 3 arg open doesn't cause a crash) unless perl 5.8+ 16 | BEGIN 17 | { if( $] < 5.008) { print "1..1\nok 1\n"; warn "skipping tests that require 3 args open\n"; exit 0; } } 18 | 19 | my $TMAX=4; 20 | print "1..$TMAX\n"; 21 | 22 | { my $out=''; 23 | open( my $fh, '>', \$out); 24 | my $doc=q{foobar}; 25 | my $t= XML::Twig->new( twig_handlers => { elt => sub { $_->flush( $fh) } }); 26 | $t->parse( $doc); 27 | is( $out, $doc, "flush to a scalar (with autoflush)"); 28 | $t->flush( $fh); 29 | is( $out, $doc, "double flush"); 30 | $t->flush(); 31 | is( $out, $doc, "triple flush"); 32 | } 33 | 34 | { 35 | my $out= ''; 36 | my $twig = XML::Twig->new( output_encoding => 'utf-8',); 37 | $twig->parse( ""); 38 | my $greet = $twig->root->insert_new_elt( last_child => 'g'); 39 | $greet->set_text("Gr\x{00FC}\x{00DF}"); 40 | open(my $fh, '>:utf8', \$out); 41 | $twig->print(\*$fh); 42 | print {*$fh} "Copyright \x{00A9} 2008 Me"; 43 | close($fh); 44 | is( $out, qq{GrüßCopyright © 2008 Me}, 45 | '$t->print and regular print mixed, with utf-8 encoding' 46 | ); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /t/test_spaces.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | use XML::Twig; 4 | 5 | $/="\n\n"; 6 | 7 | print "1..3\n"; 8 | 9 | my $twig=XML::Twig->new( keep_spaces_in => [ 'e']); 10 | test( $twig, 1); 11 | $twig=XML::Twig->new( keep_spaces_in => [ 'e', 'sub1']); 12 | test( $twig, 2); 13 | $twig=XML::Twig->new( keep_spaces => 1); 14 | test( $twig, 3); 15 | 16 | sub test 17 | { my( $twig, $test_nb)= @_; 18 | my $doc= ; chomp $doc; 19 | my $expected_res= ; chomp $expected_res; 20 | 21 | 22 | $twig->parse( $doc); 23 | 24 | my $res= $twig->sprint; 25 | $res=~ s/\n+$//; 26 | 27 | if( $res eq $expected_res) 28 | { print "ok $test_nb\n"; } 29 | else 30 | { print "not ok $test_nb\n"; 31 | warn " expected: \n$expected_res\n result: \n$res\n"; 32 | } 33 | } 34 | 35 | exit 0; 36 | 37 | __DATA__ 38 | 39 | &c;b 40 | 41 | 42 | &c;b 43 | 44 | 45 | &c;b 46 | 47 | &c; 48 | 49 | 50 | 51 | 52 | &c;b 53 | 54 | &c; 55 | 56 | 57 | 58 | 59 | &c;b 60 | 61 | &c; 62 | 63 | 64 | 65 | 66 | &c;b 67 | 68 | &c; 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /t/test_3_47.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use XML::Twig; 7 | use Test::More tests => 3; 8 | 9 | use utf8; 10 | 11 | # test CDATA sections in HTML escaping https://rt.cpan.org/Ticket/Display.html?id=86773 12 | 13 | # module => XML::Twig->new options 14 | my %html_conv= ( 'HTML::TreeBuilder' => {}, 15 | 'HTML::Tidy' => { use_tidy => 1 }, 16 | ); 17 | foreach my $module ( sort keys %html_conv) 18 | { SKIP: 19 | { eval "use $module"; 20 | skip "$module not available", 1 if 1 ; 21 | 22 | my $in = q{

Here&there v&r;

marco&company; and marco&company £ £ £ £

}; 23 | my $expected= q{

Here&there v&r;

marco&company; and marco&company £ £ £ £

}; 24 | 25 | my $parser= XML::Twig->new( %{$html_conv{$module}}); 26 | my $t = $parser->safe_parse_html($in); 27 | print $@ if $@; 28 | 29 | like $t->sprint, qr{\Q$expected\E}, "In and out are the same ($module)"; 30 | 31 | } 32 | } 33 | 34 | { # test RT #94295 https://rt.cpan.org/Public/Bug/Display.html?id=94295 35 | # in twig_handlers, '=' in regexps on attributes are turned into 'eq' 36 | my $xml= 'e1e2'; 37 | my $r; 38 | my $t= XML::Twig->new( twig_handlers => { 'e[@dn =~ /host=0/]' => sub { $r.= $_->text } }) 39 | ->parse( $xml); 40 | is( $r, 'e1', 'regexp on attribute, including an = sign'); 41 | } 42 | exit; 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /t/test2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ]> 20 | 21 |
22 | 23 | S1 I1 24 | S1 I2 25 | 26 | S1 Title 27 | S1 P1 28 | S2 P2 29 | 30 | Note P1 31 | 32 | S1 para 3 33 |
34 |
35 | 36 | S2 intro 37 | 38 | S2 Title 39 | S2 P1 40 | S2 P2 41 | S2 P3 42 |
43 | 44 | Annex Title 45 | Annex P1 46 | Annex P2 47 | 48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /t/test_variables.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | use XML::Twig; 4 | 5 | $|=1; 6 | 7 | print "1..6\n"; 8 | #warn "\n\n### warnings are normal here ###\n\n"; 9 | 10 | my $t= XML::Twig->new->parse( \*DATA); 11 | 12 | # intercept warnings 13 | $SIG{__WARN__} = sub { print STDERR @_ if( $_[0]=~ /^test/); }; 14 | 15 | 16 | my $s= $t->simplify( var_attr => 'var', variables => { 'v2' => 'elt2'}); 17 | if( $s->{elt2} eq 'elt using elt1') { print "ok 1\n" } 18 | else { print "not ok 1\n"; warn "test 1: /$s->{elt2}/ instead of 'elt using elt1'\n"; } 19 | if( $s->{elt3} eq 'elt using elt1') { print "ok 2\n" } 20 | else { print "not ok 2\n"; warn "test 2: /$s->{elt3}/ instead of 'elt using elt1'\n"; } 21 | if( $s->{elt4} eq 'elt using elt2') { print "ok 3\n"; warn "\n"; } 22 | else { print "not ok 3\n"; warn "test 3: /$s->{elt4}/ instead of 'elt using elt2'\n"; } 23 | if( $s->{elt5}->{att1} eq 'att with elt1') { print "ok 4\n" } 24 | else { print "not ok 4\n"; warn "test 4: /$s->{elt5}->{att1}/ instead of 'att with elt1'\n"; } 25 | 26 | 27 | $s= $t->simplify( variables => { 'v2' => 'elt2'}); 28 | if( $s->{elt2} eq 'elt using $v1') { print "ok 5\n" } 29 | else { print "not ok 5\n"; warn "test 5: /$s->{elt2}/ instead of 'elt using \$v1'\n"; } 30 | if( $s->{elt4} eq 'elt using elt2') { print "ok 6\n" } 31 | else { print "not ok 6\n"; warn "test 6: /$s->{elt4}/ instead of 'elt using elt2'\n"; } 32 | 33 | exit 0; 34 | 35 | __DATA__ 36 | 37 | elt1 38 | elt using $v1 39 | elt using ${v1} 40 | elt using $v2 41 | 42 | 43 | -------------------------------------------------------------------------------- /t/xmlxpath_nav.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | $|=1; 8 | 9 | my $t= XML::Twig::XPath->new; 10 | $t->parse( 11 | ' 12 | elt 1 13 | elt 2 14 | 15 | elt 3 16 | 17 | 18 | 2 19 | 3 20 | 21 | elt 3 22 | '); 23 | 24 | my @data= grep { !/^##/ && m{\S} } ; 25 | 26 | my @exp; 27 | my %result; 28 | 29 | foreach( @data) 30 | { chomp; 31 | my ($exp, $id_list) = split /\s*=>\s*/ ; 32 | $result{$exp}= $id_list; 33 | push @exp, $exp; 34 | } 35 | 36 | my $nb_tests= keys %result; 37 | print "1..$nb_tests\n"; 38 | 39 | my $i=1; 40 | 41 | foreach my $exp ( @exp) 42 | { my $expected_result= $result{$exp}; 43 | my $result_elt= $t->root->first_child( $exp); 44 | my $result= $result_elt ? $result_elt->att( 'id') : 'none'; 45 | 46 | if( $result eq $expected_result) 47 | { print "ok $i\n"; } 48 | else 49 | { print "nok $i\n"; 50 | print STDERR "$exp: expected $expected_result - real $result\n"; 51 | } 52 | $i++; 53 | } 54 | 55 | exit 0; 56 | 57 | __DATA__ 58 | elt => elt-1 59 | elt[@id="elt-4"] => elt-4 60 | elt[@id="elt-3"] => none 61 | *[@att > 1] => elt-2 62 | elt2[2] => elt2-2 63 | ##elt2[./elt2] => elt2-2 64 | elt3 => none 65 | -------------------------------------------------------------------------------- /t/test_attregexp_cond.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use XML::Twig; 5 | 6 | $|=1; 7 | 8 | my $i=0; 9 | my $failed=0; 10 | 11 | my $TMAX=4; # do not forget to update! 12 | 13 | print "1..$TMAX\n"; 14 | 15 | $i++; 16 | print "ok $i\n"; # loading 17 | 18 | my $t= XML::Twig->new( 19 | twig_handlers => 20 | { 'elt[@att=~/^v/]' => sub { $i++; 21 | if( $_->att( 'ok') eq "ok") 22 | { print "ok $i\n"; 23 | } 24 | else 25 | { print "NOK $i\n"; 26 | # print STDERR "id: ", $_->att( 'id'), "\n"; 27 | } 28 | }, 29 | 'elt[@change=~/^now$/]' => sub { $_[0]->setTwigHandler( 30 | 'elt[@att=~/^new/]' => 31 | sub { $i++; 32 | if( $_->att( 'ok') eq "ok") 33 | { print "ok $i\n"; } 34 | else 35 | { print "NOK $i\n"; 36 | # print STDERR "id: ", $_->att( 'id'), "\n"; 37 | } 38 | }); 39 | }, 40 | }, 41 | ); 42 | $t->parse( \*DATA); 43 | 44 | exit 0; 45 | 46 | __DATA__ 47 | 48 | foo 49 | 50 | q 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /t/xmlxpath_21allnodes.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test; 8 | plan( tests => 13); 9 | 10 | 11 | use XML::Twig::XPath; 12 | ok(1); 13 | 14 | my $t= XML::Twig::XPath->new->parse( \*DATA); 15 | 16 | ok( $t); 17 | 18 | my @nodes; 19 | @nodes = $t->findnodes( '//GGG/ancestor::*'); 20 | ok(@nodes, 4); 21 | 22 | @nodes = $t->findnodes( '//GGG/descendant::*'); 23 | ok(@nodes, 3); 24 | 25 | @nodes = $t->findnodes( '//GGG/following::*'); 26 | ok(@nodes, 3); 27 | ok($nodes[0]->getName, "VVV"); 28 | ok($nodes[1]->getName, "CCC"); 29 | ok($nodes[2]->getName, "DDD"); 30 | 31 | @nodes = $t->findnodes( '//GGG/preceding::*'); 32 | ok(@nodes, 5); 33 | ok($nodes[0]->getName, "BBB"); # document order, not HHH 34 | 35 | @nodes = $t->findnodes( '//GGG/self::*'); 36 | ok(@nodes, 1); 37 | ok($nodes[0]->getName, "GGG"); 38 | 39 | @nodes = $t->findnodes( '//GGG/ancestor::* | //GGG/descendant::* | //GGG/following::* | //GGG/preceding::* | //GGG/self::*'); 40 | ok(@nodes, 16); 41 | 42 | exit 0; 43 | 44 | __DATA__ 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /t/test_expand_external_entities.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use Carp; 5 | 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | 10 | $|=1; 11 | 12 | use XML::Twig; 13 | 14 | my $TMAX=3; 15 | 16 | print "1..$TMAX\n"; 17 | 18 | my $xml_file= File::Spec->catfile( "t", "test_expand_external_entities.xml"); 19 | my $dtd_file= File::Spec->catfile( "t", "test_expand_external_entities.dtd"); 20 | 21 | my( $xml, $dtd, $xml_expanded, %ent); 22 | { local undef $/; 23 | open XML, "<$xml_file" or die "cannot open $xml_file: $!"; 24 | $xml= ; 25 | close XML; 26 | open DTD, "<$dtd_file" or die "cannot open $dtd_file: $!"; 27 | $dtd= ; 28 | close DTD; 29 | } 30 | 31 | # extract entities 32 | while( $dtd=~ m{}gx) { $ent{$1}= $2; } #" 33 | # replace in xml 34 | ($xml_expanded= $xml)=~ s{&(\w+);}{$ent{$1}}g; 35 | 36 | { 37 | my $t= XML::Twig->new( load_DTD => 1); 38 | $t->set_expand_external_entities; 39 | $t->parsefile( $xml_file); 40 | is( normalize_xml( $t->sprint), normalize_xml( $xml_expanded), "expanded document"); 41 | } 42 | 43 | { 44 | my $t= XML::Twig->new( load_DTD => 1, expand_external_ents => 1); 45 | $t->parsefile( $xml_file); 46 | is( normalize_xml( $t->sprint), normalize_xml( $xml_expanded), "expanded document"); 47 | } 48 | 49 | { 50 | (my $xml_no_dtd= $xml_expanded)=~ s{^}{}s; 51 | my $t= XML::Twig->new( load_DTD => 1, expand_external_ents => 1, do_not_output_DTD => 1); 52 | $t->parsefile( $xml_file); 53 | is( normalize_xml( $t->sprint), normalize_xml( $xml_no_dtd), "expanded document"); 54 | } 55 | 56 | exit 0; 57 | -------------------------------------------------------------------------------- /t/is_field.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use XML::Twig; 5 | 6 | $|=1; 7 | 8 | my $i=1; 9 | 10 | my $TMAX=43; # do not forget to update! 11 | 12 | print "1..$TMAX\n"; 13 | 14 | print "ok $i\n"; # loading 15 | $i++; 16 | 17 | my $t= XML::Twig->new(); 18 | $t->parse( \*DATA); 19 | 20 | 21 | foreach my $elt ($t->descendants) 22 | { if( ($elt->tag eq 'field') && !$elt->is_field) 23 | { print "not ok $i "; 24 | warn $elt->id, " not recognized as field\n"; 25 | } 26 | elsif( ($elt->tag ne 'field') && $elt->is_field) 27 | { print "not ok $i "; 28 | my $elt_id= $elt->id || $elt->text; 29 | warn " $elt_id recognized as field\n"; 30 | } 31 | else 32 | { print "ok $i\n"; } 33 | $i++; 34 | } 35 | 36 | exit 0; 37 | 38 | 39 | __DATA__ 40 | 41 | field 1 42 | 43 | text 1 text 2 44 | text 3 field 2 text 4 45 | text 5field 46 | field 3 47 | field 4 48 | field 5field 6 49 | 50 | field 7 51 | field 8 52 | 53 | field 9 54 | 0 55 | 56 | a field 10 57 | 58 | 59 | -------------------------------------------------------------------------------- /t/test_pos.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | use Carp; 4 | 5 | $|=1; 6 | 7 | # test for the various conditions in navigation methods 8 | 9 | use XML::Twig; 10 | 11 | 12 | my $t= XML::Twig->new; 13 | $t->parse( 14 | ' 15 | an element 16 | an element 17 | an element 18 | an element 19 | an element 20 | an element 21 | an element 22 | '); 23 | 24 | my @data=; 25 | my @data_without_comments= grep { !m{^\s*(#.*)?$} } @data; 26 | my @test= map { s{\#.*$}{}; $_ } @data_without_comments; 27 | 28 | #my @test= map { s{#.*$}{}; $_ } grep { !m{^\s*(#.*)?$} } ; 29 | 30 | my $nb_test= @test; 31 | print "1..$nb_test\n"; 32 | 33 | my $i=1; 34 | foreach my $test (@test) 35 | { my( $id, $exp, $expected_pos)= split /\t+/, $test; 36 | chomp $expected_pos; 37 | $exp= '' if( $exp eq '_'); 38 | test( $i++, $id, $exp, $expected_pos); 39 | } 40 | 41 | 42 | sub test 43 | { my( $i, $id, $exp, $expected_pos)= @_; 44 | my $elt= $t->elt_id( $id); 45 | my $pos= $elt->pos( $exp); 46 | 47 | if( $pos == $expected_pos) 48 | { print "ok $i\n"; } 49 | else 50 | { print "not ok $i\n"; 51 | my $filter= $exp ? " filter: $exp" : ''; 52 | warn "test $i: $id $filter - expected $expected_pos, actual $pos\n"; 53 | } 54 | } 55 | 56 | exit 0; 57 | 58 | __DATA__ 59 | #id exp expected 60 | doc _ 1 61 | doc elt1 0 62 | doc toto 0 63 | elt1_1 _ 1 64 | elt1_1 elt1 1 65 | elt1_1 toto 0 66 | elt1_2 _ 2 67 | elt1_2 elt1 2 68 | elt1_2 toto 0 69 | elt2_1 _ 4 70 | elt2_1 elt1 0 71 | elt2_1 elt2 1 72 | elt2_1 toto 0 73 | elt2_2 _ 6 74 | elt2_2 elt1 0 75 | elt2_2 elt2 2 76 | elt2_2 toto 0 77 | -------------------------------------------------------------------------------- /t/test_class_selector.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use XML::Twig; 7 | 8 | use File::Spec; 9 | use lib File::Spec->catdir(File::Spec->curdir,'t'); 10 | use tools; 11 | 12 | my @DATA; 13 | while( ) { chomp; my( $cond, $expected)= split /\s*=>\s*/; push @DATA, [$cond, $expected]; } 14 | 15 | my $TMAX= 20; 16 | 17 | print "1..$TMAX\n"; 18 | 19 | my $doc=q{e1e2e3}; 20 | my $doc_dot=q{wrong e1wrong e2wrong e3e1e2e3}; 21 | 22 | my $t= XML::Twig->parse( $doc); 23 | 24 | foreach my $test (@DATA) 25 | { my( $cond, $expected)= @$test; 26 | my $got= join '', map { $_->text } $t->root->children( $cond); 27 | is( $got, $expected, "navigation: $cond" ); 28 | } 29 | 30 | if( $] > 5.008) 31 | { 32 | foreach my $test (@DATA) 33 | { my( $cond, $expected)= @$test; 34 | my $got=''; 35 | XML::Twig->new( twig_handlers => { $cond => sub { $got.= $_->text } }, 36 | css_sel => 1, 37 | ) 38 | ->parse( $doc); 39 | is( $got, $expected, "handlers (css_sel enabled): $cond" ); 40 | } 41 | 42 | foreach my $test (@DATA) 43 | { my( $cond, $expected)= @$test; 44 | next if $cond !~ m{^e}; 45 | my $got=''; 46 | XML::Twig->new( twig_handlers => { $cond => sub { $got.= $_->text } },) 47 | ->parse( $doc_dot); 48 | is( $got, $expected, "handlers (css_sel NOT enabled): $cond" ); 49 | } 50 | } 51 | else 52 | { skip( 12, 'not tested under perl < 5.8'); } 53 | 54 | 55 | 56 | 57 | __DATA__ 58 | e.c1 => e1e2 59 | e.c1[@a="v1"] => e2 60 | e.c1[@a] => e2 61 | e.c1[@a="v2"] => 62 | *.c1[@a="v1"] => e2 63 | *.c1[@a="v2" or @a="v1"] => e2 64 | .c1[@a="v1"] => e2 65 | .c1[@a="v2" or @a="v1"] => e2 66 | -------------------------------------------------------------------------------- /upd_changes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use DDP; 7 | use Perl6::Slurp; 8 | 9 | my %date= map { split /\s+/ } ; 10 | 11 | my $changes= slurp 'Changes'; 12 | 13 | my @types= qw( added fixed improved changed removed 14 | 15 | for ($changes) 16 | { s{\nversion\s*(\d\.\d\d)\s*date\s*:\s*([\d-]*)\s*#\s*(.*)} 17 | { my $d= $2 || $date{$1}; 18 | my $c= $3 ? " - $3" : ""; 19 | "\n$1 - $d$c"; 20 | }eg; 21 | 22 | s{Changes in (\d.\d\d)} 23 | { $1 - $date{$1} }g; 24 | } 25 | 26 | open( my $out, '>', 'new_changes') or die "cannot create new_changes: $!"; 27 | print {$out} $changes; 28 | 29 | __DATA__ 30 | 1.6 1999-10-05 31 | 1.7 1999-12-07 32 | 1.8 1999-12-17 33 | 1.9 2000-02-17 34 | 1.10 2000-03-24 35 | 2.00 2000-06-05 36 | 2.01 2000-08-18 37 | 2.02 2001-01-16 38 | 3.00 2002-01-09 39 | 3.01 2002-01-09 40 | 3.02 2002-01-16 41 | 3.03 2002-03-26 42 | 3.04 2002-04-01 43 | 3.05 2002-07-09 44 | 3.06 2002-09-17 45 | 3.07 2002-09-17 46 | 3.08 2002-09-17 47 | 3.09 2002-11-10 48 | 3.10 2003-06-09 49 | 3.11 2003-08-28 50 | 3.12 2004-01-29 51 | 3.13 2004-03-16 52 | 3.14 2004-03-17 53 | 3.15 2004-04-05 54 | 3.16 2005-02-11 55 | 3.17 2005-03-16 56 | 3.18 2005-08-08 57 | 3.19 2005-08-10 58 | 3.20 2005-08-11 59 | 3.21 2005-08-12 60 | 3.22 2005-10-14 61 | 3.23 2006-01-23 62 | 3.24 2006-05-09 63 | 3.25 2006-05-10 64 | 3.26 2006-07-01 65 | 3.28 2007-01-05 66 | 3.29 2007-01-22 67 | 3.30 2007-11-06 68 | 3.31 2007-11-07 69 | 3.32 2007-11-13 70 | 3.33 2010-01-15 71 | 3.34 2010-01-18 72 | 3.35 2010-05-15 73 | 3.36 2010-10-07 74 | 3.37 2010-10-09 75 | 3.38 2011-02-26 76 | 3.39 2011-09-21 77 | 3.40 2012-05-10 78 | 3.41 2012-08-08 79 | 3.42 2012-11-08 80 | 3.43 2013-05-12 81 | 3.44 2013-05-13 82 | 83 | -------------------------------------------------------------------------------- /t/test_need_use_bytes.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | 4 | # tests that require IO::Scalar to run 5 | use strict; 6 | use Carp; 7 | 8 | use File::Spec; 9 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 10 | use tools; 11 | 12 | #$|=1; 13 | my $DEBUG=0; 14 | 15 | use XML::Twig; 16 | 17 | BEGIN 18 | { eval "use bytes"; 19 | if( $@) 20 | { print "1..1\nok 1\n"; 21 | warn "skipping, need to be able to use bytes\n"; 22 | exit; 23 | } 24 | } 25 | 26 | print "1..2\n"; 27 | 28 | my $text= "été"; 29 | my $text_safe= "été"; 30 | my $text_safe_hex= "été"; 31 | my $doc=qq{\n$text}; 32 | my $doc_safe=qq{\n$text_safe}; 33 | my $doc_safe_hex=qq{\n$text_safe_hex}; 34 | 35 | my $t= XML::Twig->new()->parse( $doc); 36 | 37 | if( $] == 5.008) 38 | { skip( 2); } 39 | else 40 | { $t->set_output_text_filter( sub { my $text= shift; 41 | use bytes; 42 | $text=~ s{([\xC0-\xDF].|[\xE0-\xEF]..|[\xF0-\xFF]...)} 43 | {XML::Twig::_XmlUtf8Decode($1)}egs; 44 | return $text; 45 | } 46 | ); 47 | is( $t->sprint, $doc_safe, 'safe with _XmlUtf8Decode'); # test 338 48 | $t->set_output_text_filter( sub { my $text= shift; 49 | use bytes; 50 | $text=~ s{([\xC0-\xDF].|[\xE0-\xEF]..|[\xF0-\xFF]...)} 51 | {XML::Twig::_XmlUtf8Decode($1, 1)}egs; 52 | return $text; 53 | } 54 | ); 55 | is( $t->sprint, $doc_safe_hex, 'safe_hex with _XmlUtf8Decode'); # test 339 56 | } 57 | 58 | 59 | exit 0; 60 | -------------------------------------------------------------------------------- /t/test_cdata.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use XML::Twig; 6 | 7 | $|=1; 8 | 9 | $/= "\n\n"; 10 | my $xml= ; 11 | 12 | print "1..4\n"; 13 | 14 | my( $t, $result, $expected_result); 15 | 16 | $t= XML::Twig->new( twig_handlers => { 'ehtml/#CDATA' => sub { $_->set_asis; } }); 17 | $t->parse( $xml); 18 | $result= $t->sprint; 19 | ($expected_result=)=~ s{\n*$}{}s; 20 | if( $result eq $expected_result) { print "ok 1\n"; } 21 | else { print "not ok 1\n"; warn "expected: $expected_result\n result : $result"; } 22 | 23 | $t= XML::Twig->new( twig_handlers => { 'ehtml/#CDATA' => sub { $_->remove_cdata; } }); 24 | $t->parse( $xml); 25 | $result= $t->sprint; 26 | ($expected_result=)=~ s{\n*$}{}s; 27 | if( $result eq $expected_result) { print "ok 2\n"; } 28 | else { print "not ok 2\n"; warn "expected: $expected_result\n result : $result"; } 29 | 30 | $t= XML::Twig->new( keep_encoding => 1, twig_handlers => { 'ehtml/#CDATA' => sub { $_->set_asis; } }); 31 | $t->parse( $xml); 32 | $result= $t->sprint; 33 | ($expected_result=)=~ s{\n*$}{}s; 34 | if( $result eq $expected_result) { print "ok 3\n"; } 35 | else { print "not ok 3\n"; warn "test keep_encoding / asis\n expected: $expected_result\n result : $result"; } 36 | 37 | $t= XML::Twig->new( keep_encoding => 1, twig_handlers => { 'ehtml/#CDATA' => sub { $_->remove_cdata; } }); 38 | $t->parse( $xml); 39 | $result= $t->sprint; 40 | ($expected_result=)=~ s{\n*$}{}s; 41 | if( $result eq $expected_result) { print "ok 4\n"; } 42 | else { print "not ok 4\n"; warn "test keep_encoding / remove_cdata\n expected: $expected_result\n result : $result"; } 43 | 44 | exit 0; 45 | 46 | __DATA__ 47 | 48 | text 49 | world & all]]> 50 | 51 | 52 | texthello
world & all
53 | 54 | texthello<br>world & all 55 | 56 | texthello
world & all
57 | 58 | texthello<br>world & all 59 | 60 | -------------------------------------------------------------------------------- /t/test_safe_encode.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use File::Spec; 6 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 7 | use tools; 8 | 9 | use XML::Twig; 10 | 11 | my $DEBUG=0; 12 | 13 | print "1..8\n"; 14 | 15 | if( $] >= 5.006) { eval "use utf8;"; } 16 | 17 | # suitable for perl 5.6.* 18 | my $doc=q{<élément att="été">été}; 19 | (my $safe_xml_doc= $doc)=~ s{é}{é}g; 20 | (my $safe_hex_doc= $doc)=~ s{é}{é}g; 21 | (my $text_safe_xml_doc= $doc)=~ s{été}{ét&233;}g; 22 | (my $text_safe_hex_doc= $doc)=~ s{é}{ét&xe9;}g; 23 | 24 | is( XML::Twig->new( output_filter => 'safe')->parse( $doc)->sprint, $safe_xml_doc, "output_filter => 'safe'"); 25 | is( XML::Twig->new( output_filter => 'safe_hex')->parse( $doc)->sprint, $safe_hex_doc, "output_filter => 'safe_hex'"); 26 | is( XML::Twig->new( output_text_filter => 'safe')->parse( $doc)->sprint, $safe_xml_doc, "output_text_filter => 'safe'"); 27 | is( XML::Twig->new( output_text_filter => 'safe_hex')->parse( $doc)->sprint, $safe_hex_doc, "output_text_filter => 'safe_hex'"); 28 | 29 | # suitable for 5.8.* and above (you can't have utf-8 hash keys before that) 30 | 31 | if( $] < 5.008) 32 | { skip( 4 => "cannot process utf-8 attribute names with a perl before 5.8"); } 33 | else 34 | { 35 | my $doc='<élément atté="été">été'; 36 | (my $safe_xml_doc= $doc)=~ s{é}{é}g; 37 | (my $safe_hex_doc= $doc)=~ s{é}{é}g; 38 | (my $text_safe_xml_doc= $doc)=~ s{été}{ét&233;}g; 39 | (my $text_safe_hex_doc= $doc)=~ s{é}{ét&xe9;}g; 40 | 41 | is( XML::Twig->new( output_filter => 'safe')->parse( $doc)->sprint, $safe_xml_doc, "output_filter => 'safe'"); 42 | is( XML::Twig->new( output_filter => 'safe_hex')->parse( $doc)->sprint, $safe_hex_doc, "output_filter => 'safe_hex'"); 43 | is( XML::Twig->new( output_text_filter => 'safe')->parse( $doc)->sprint, $safe_xml_doc, "output_text_filter => 'safe'"); 44 | is( XML::Twig->new( output_text_filter => 'safe_hex')->parse( $doc)->sprint, $safe_hex_doc, "output_text_filter => 'safe_hex'"); 45 | } 46 | -------------------------------------------------------------------------------- /t/test_pi_handler.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | use Carp; 4 | 5 | # test for the various conditions in navigation methods 6 | 7 | $|=1; 8 | 9 | use XML::Twig; 10 | 11 | if( $] < 5.008) 12 | { warn "skipped, not tested under perl < 5.8\n"; print "1..1\nok 1\n"; exit 0; } 13 | 14 | my $nb_tests=4; 15 | print "1..$nb_tests\n"; 16 | 17 | my $result; 18 | my $t= XML::Twig->new( pi => 'process', 19 | twig_handlers => { '?pi' => sub { $result .=$_->text; } }, 20 | ); 21 | $t->parse( q{}); 22 | my $expected= ''; 23 | if( $result eq $expected) 24 | { print "ok 1\n"; } 25 | else 26 | { print "not ok 1\n"; 27 | warn "expected: $expected\nfound : $result\n"; 28 | } 29 | 30 | $result=''; 31 | $t= XML::Twig->new( pi => 'process', 32 | twig_handlers => { '?pi' => sub { $result .=$_->text; } }, 33 | ); 34 | $t->parse( q{}); 35 | $expected= ''; 36 | if( $result eq $expected) 37 | { print "ok 2\n"; } 38 | else 39 | { print "not ok 2\n"; 40 | warn "expected: $expected\nfound : $result\n"; 41 | } 42 | 43 | $result=''; 44 | $t= XML::Twig->new( twig_handlers => { 'doc' => sub { $result= $_->{extra_data}; } },); 45 | $t->parse( q{}); 46 | $expected= ''; 47 | if( $result eq $expected) 48 | { print "ok 3\n"; } 49 | else 50 | { print "not ok 3\n"; 51 | warn "expected: $expected\nfound : $result\n"; 52 | } 53 | 54 | 55 | $result=''; 56 | $t= XML::Twig->new( pi => 'process', 57 | twig_roots => { '?pi' => sub { $result= $_->target . "/" . $_->data; }, 58 | elt => sub { }, 59 | }); 60 | $t->parse( q{}); 61 | $expected= 'pi/pi in doc '; 62 | if( $result eq $expected) 63 | { print "ok 4\n"; } 64 | else 65 | { print "not ok 4\n"; 66 | warn "expected: /$expected/\nfound : /$result/\n"; 67 | } 68 | 69 | exit 0; 70 | -------------------------------------------------------------------------------- /t/xmlxpath_test_with_handlers.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 3 | 4 | use Test; 5 | plan( tests => 7); 6 | 7 | use XML::Twig::XPath; 8 | 9 | $|=1; 10 | 11 | my $doc= 12 | ' 13 | elt 1 14 | elt 2 15 | 16 | elt 3 17 | 18 | 19 | 2 20 | 3 21 | 22 | 23 | 24 | 2 25 | 3 26 | 27 | 28 | 2 29 | 3 30 | 31 | in_elt6-1 32 | in_elt7-1 33 | in_elt7-2 34 | 35 | <:elt id=":elt">yep, that is a valid name 36 | ' 37 | ; 38 | 39 | my $t= XML::Twig::XPath->new( twig_handlers => 40 | { elt5 => sub { my @res1= $_->findnodes( './elt3/elt4[@att_int="3"] | elt3'); 41 | ok( ids( @res1), "elt3-1 - elt4-2 - elt3-2 - elt4-4"); # 1 42 | ok( $_->field( 'elt7[@id="elt7-2"]'), "in_elt7-2"); # 2 43 | ok( $_->findvalue( 'elt7[@id="elt7-2"]'), "in_elt7-2"); # 3 44 | ok( $_->findvalue( 'elt7[preceding-sibling::*[1][self::elt6]]'), "in_elt7-1"); # 4 45 | ok( $_->findvalue( 'elt7[preceding-sibling::elt6]'), "in_elt7-1in_elt7-2"); # 5 46 | ok( $_->findvalue( "elt7"), "in_elt7-1in_elt7-2"); # 6 47 | }, 48 | }, 49 | ); 50 | $t->parse( $doc); 51 | ok( ids( $t->findnodes( '//elt3/elt4[@att_int="3"] | //elt3') ), "elt3-1 - elt4-2 - elt3-2 - elt4-4"); # 7 52 | 53 | exit 0; 54 | 55 | sub ids 56 | { return join( " - ", map { $_->id } @_); } 57 | -------------------------------------------------------------------------------- /t/test_3_55.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use XML::Twig; 7 | 8 | use File::Spec; 9 | use lib File::Spec->catdir( File::Spec->curdir, "t" ); 10 | use tools; 11 | 12 | my $TMAX = 28; 13 | print "1..$TMAX\n"; 14 | 15 | # fixing holes in test coverage (and bugs in the code) 16 | { 17 | my $doc = ' 18 | 0 19 | 1 20 | 1 21 | 0 22 | foo 23 | '; 24 | my ( $res_e0, $res_e1, $res_c0, $res_c1, $res_efoo, $res_cfoo ); 25 | my %tests = ( 26 | 'c[string()=0]' => 'e1e4', 27 | 'c[string()=0.0]' => 'e1e4', 28 | 'c[string()=1]' => 'e2e3', 29 | 'c[string()=1.0]' => 'e2e3', 30 | 'c[string()="foo"]' => 'e5', 31 | 'c[string() >= 1]' => 'e2e3', 32 | 'c[string() >= 0]' => 'e1e2e3e4', 33 | 'c[string() != 0]' => 'e2e3', 34 | 'c[string() < 1]' => 'e1e4', 35 | 'c[string() <= 1]' => 'e1e2e3e4', 36 | 'c[string() <= 0]' => 'e1e4', 37 | 'c[string() < 0]' => '', 38 | 'c[string() > 1]' => '', 39 | 'c[string() =~ /^1$/]' => 'e2e3', 40 | ); 41 | my $handlers = {}; 42 | my $res={}; 43 | foreach my $sel ( keys %tests ) { 44 | $handlers->{$sel} = sub { add_parent_id( $res, $sel ); }; 45 | my $esel = esel($sel); 46 | $handlers->{$esel} = sub { add_id( $res, $esel ); }; 47 | } 48 | 49 | XML::Twig->new( twig_handlers => $handlers )->parse($doc); 50 | 51 | foreach my $sel ( keys %tests ) { 52 | is( $res->{$sel}, $tests{$sel}, "testing twig_handlers trigger $sel" ); 53 | my $esel = esel($sel); 54 | is( $res->{$esel}, $tests{$sel}, "testing twig_handlers trigger $esel" ); 55 | } 56 | 57 | } 58 | 59 | sub esel { 60 | my ($sel) = @_; 61 | return $sel =~ s{\Qc[string()}{e[string(c)}r; 62 | } 63 | 64 | sub add_id { 65 | my ( $res, $key ) = @_; 66 | $res->{$key} .= $_->id; 67 | 1; 68 | } 69 | 70 | sub add_parent_id { 71 | my ( $res, $key ) = @_; 72 | $res->{$key} .= $_->parent->id; 73 | 1; 74 | } 75 | 76 | exit; 77 | 78 | -------------------------------------------------------------------------------- /t/test_comment_handler.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | use Carp; 4 | 5 | # test for the various conditions in navigation methods 6 | 7 | use XML::Twig; 8 | 9 | if( $] < 5.008) 10 | { warn "skipped, not tested under perl < 5.8\n"; print "1..1\nok 1\n"; exit 0; } 11 | 12 | my $nb_tests=4; 13 | print "1..$nb_tests\n"; 14 | 15 | { 16 | my $result; 17 | my $t= XML::Twig->new( comments => 'process', 18 | twig_handlers => { '#COMMENT' => sub { $result .=$_->text; } }, 19 | ); 20 | $t->parse( q{}); 21 | my $expected= ' comment in doc '; 22 | if( $result eq $expected) 23 | { print "ok 1\n"; } 24 | else 25 | { print "not ok 1\n"; 26 | warn "expected: $expected\nfound : $result\n"; 27 | } 28 | } 29 | 30 | { 31 | my $result=''; 32 | my $t= XML::Twig->new( comments => 'process', 33 | twig_handlers => { '#COMMENT' => sub { $result .=$_->text; } }, 34 | ); 35 | $t->parse( q{}); 36 | my $expected= ' comment in doc '; 37 | if( $result eq $expected) 38 | { print "ok 2\n"; } 39 | else 40 | { print "not ok 2\n"; 41 | warn "expected: $expected\nfound : $result\n"; 42 | } 43 | } 44 | 45 | { 46 | my $result=''; 47 | my $t= XML::Twig->new( twig_handlers => { 'doc' => sub { $result= $_->{extra_data}; } },); 48 | $t->parse( q{}); 49 | my $expected= ''; 50 | if( $result eq $expected) 51 | { print "ok 3\n"; } 52 | else 53 | { print "not ok 3\n"; 54 | warn "expected: $expected\nfound : $result\n"; 55 | } 56 | } 57 | 58 | { 59 | my $result=''; 60 | my $t= XML::Twig->new( comments => 'process', 61 | twig_roots => { '/#COMMENT' => sub { $result= $_->{extra_data}; }, 62 | elt => sub { }, 63 | }); 64 | $t->parse( q{}); 65 | my $expected= ''; # This is a bug! 66 | if( $result eq $expected) 67 | { print "ok 4\n"; } 68 | else 69 | { print "not ok 4\n"; 70 | warn "expected: $expected\nfound : $result\n"; 71 | } 72 | } 73 | 74 | exit 0; 75 | 76 | -------------------------------------------------------------------------------- /t/test_erase.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use XML::Twig; 5 | 6 | $|=1; 7 | 8 | my $TMAX=1; # do not forget to update! 9 | print "1..$TMAX\n"; 10 | 11 | undef $/; 12 | my $doc=; 13 | 14 | my $t= XML::Twig->new(keep_spaces => 1); 15 | $t->parse( $doc); 16 | foreach my $erase ($t->descendants( 'erase')) 17 | { $erase->erase; } 18 | my $result=$t->sprint; 19 | $result=~ s{\s*$}{}s; # remove trailing spaces (and \n) 20 | 21 | my $expected_result= $doc; 22 | $expected_result=~ s{}{}g; 23 | $expected_result=~ s{\s*$}{}s; # remove trailing spaces (and \n) 24 | 25 | if( $result eq $expected_result) 26 | { print "ok 1\n"; } 27 | else 28 | { print "not ok 1\n"; 29 | print STDERR "expected: \n$expected_result\n", 30 | "real: \n$result\n"; 31 | } 32 | 33 | exit 0; 34 | 35 | 36 | __DATA__ 37 | 38 | 39 | 40 | 41 | text 42 | text (1) 43 | text text (2) 44 | 45 | 46 | 47 | 48 | 49 | 50 | text (3) 51 | text text (4) 52 | text (5) text (6) 53 | text (7)text (8) text (9) 54 | text (10) 55 | text (11) 56 | text 57 | 58 | 59 | 60 | text (12) 61 | text (13)text (14) 62 | text (15) text (16) 63 | text (17)text (18) text (19) 64 | text (20)child/> 65 | text (21)child/> 66 | text (22) 67 | 68 | 69 | -------------------------------------------------------------------------------- /t/test_unique_xpath.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use File::Spec; 6 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 7 | use tools; 8 | 9 | use XML::Twig; 10 | print "1..65\n"; 11 | 12 | my $t= XML::Twig->new->parse( \*DATA); 13 | 14 | foreach my $c ($t->descendants( 'c')) 15 | { is( $c->xpath, $c->text, "xpath"); 16 | is( $t->findvalue( $c->text), $c->text, "findvalue (>0)"); 17 | } 18 | foreach my $d ($t->descendants( 'd')) 19 | { is( $t->findvalue( $d->text), $d->text, "findvalue (<0)"); } 20 | 21 | foreach( 1..4) 22 | { is( $_, $t->root->first_child( "[$_]")->att( 'pos'), "first_child[$_]"); 23 | is( 5-$_, $t->root->first_child( "[-$_]")->att( 'pos'), "first_child[-$_]"); 24 | is( $_, $t->root->first_child( "b[$_]")->att( 'pos'), "first_child b[$_]"); 25 | is( 5-$_, $t->root->first_child( "b[-$_]")->att( 'pos'), "first_child b[-$_]"); 26 | } 27 | 28 | my $e= $t->get_xpath( '/a/b[-1]/e', 0); 29 | foreach( 1..4) 30 | { is( $_, $e->first_child( "f[$_]")->att( 'fpos'), "first_child f[$_]"); 31 | is( 5-$_, $e->first_child( "f[-$_]")->att( 'fpos'), "first_child f[-$_]"); 32 | is( $_, $e->first_child( "g[$_]")->att( 'gpos'), "first_child g[$_]"); 33 | is( 5-$_, $e->first_child( "g[-$_]")->att( 'gpos'), "first_child g[-$_]"); 34 | } 35 | 36 | foreach( 1..8) 37 | { is( $_, $e->first_child( "[$_]")->att( 'pos'), "first_child [$_]"); 38 | is( 9-$_, $e->first_child( "[-$_]")->att( 'pos'), "first_child [-$_]"); 39 | } 40 | 41 | 42 | exit 0; 43 | 44 | __DATA__ 45 | 46 | 47 | /a/b[1]/c[1] 48 | /a/b[1]/c[2] 49 | /a/b[-4]/d[-2] 50 | /a/b[-4]/d[-1] 51 | 52 | 53 | /a/b[2]/c[1] 54 | /a/b[-3]/d[-2] 55 | /a/b[-3]/d[-1] 56 | tata 57 | /a/b[2]/c[2] 58 | 59 | 60 | /a/b[3]/c 61 | 62 | 63 | titi 64 | /a/b[4]/c 65 | /a/b[4]/d[-1] 66 | tutu 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /t/test_class_methods.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | 4 | # testing methods on class attribute: 5 | # class set_class add_to_class att_to_class add_att_to_class move_att_to_class 6 | # tag_to_class add_tag_to_class set_tag_class in_class 7 | 8 | use strict; 9 | use Carp; 10 | 11 | use File::Spec; 12 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 13 | use tools; 14 | 15 | use XML::Twig; 16 | 17 | my $DEBUG=0; 18 | 19 | my $TMAX=26; 20 | 21 | print "1..$TMAX\n"; 22 | 23 | { 24 | my $root= XML::Twig->new->parse( q{})->root; 25 | nok( $root->class, "no class"); 26 | $root->set_class( 'foo'); 27 | is( $root->class, 'foo', 'set_class'); 28 | $root->set_class( 'bar'); 29 | is( $root->class, 'bar', 'set_class'); 30 | ok( $root->in_class( 'bar'), 'in_class (ok)'); 31 | nok( $root->in_class( 'foo'), 'in_class (nok)'); 32 | $root->add_to_class( 'foo'); 33 | ok( $root->in_class( 'bar'), 'in_class (ok)'); 34 | ok( $root->in_class( 'foo'), 'in_class (ok)'); 35 | nok( $root->in_class( 'baz'), 'in_class (nok)'); 36 | $root->tag_to_class; 37 | is( $root->class, 'doc', 'tag_to__class'); 38 | ok( $root->in_class( 'doc'), 'in_class (ok)'); 39 | nok( $root->in_class( 'foo'), 'in_class (nok)'); 40 | $root->tag_to_class; 41 | is( $root->class, 'doc', 'tag_to_class (with existing class)'); 42 | $root->add_tag_to_class; 43 | is( $root->class, 'doc', 'add_tag_to_class'); 44 | $root->att_to_class( 'att1'); 45 | is( $root->class, 'val1', 'att_to_class'); 46 | $root->att_to_class( 'att1'); 47 | is( $root->class, 'val1', 'att_to_class (with existing class)'); 48 | $root->add_att_to_class( 'att'); 49 | is( $root->class, 'val1', 'att_to_class (non existing att)'); 50 | $root->add_att_to_class( 'att2'); 51 | is( $root->class, 'val1 val2', 'att_to_class (2 classes now)'); 52 | ok( $root->in_class( 'val1'), 'in_class'); 53 | ok( $root->in_class( 'val2'), 'in_class'); 54 | nok( $root->in_class( 'val'), 'in_class (nok)'); 55 | $root->set_tag_class( 'new'); 56 | is( $root->sprint, '', 'set_tag_class'); 57 | $root->move_att_to_class( 'att2'); 58 | is( $root->sprint, '', 'set_tag_class'); 59 | 60 | ok( $root->matches( '.doc'), 'match on class (first)'); 61 | ok( $root->matches( '.val1'), 'match on class (middle)'); 62 | ok( $root->matches( '.val2'), 'match on class (last)'); 63 | nok( $root->matches( '.val'), 'match on class (not good)'); 64 | 65 | } 66 | 67 | 68 | exit 0; 69 | -------------------------------------------------------------------------------- /t/test_xml_split_g.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use Carp; 5 | 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | use Config; 10 | my $devnull = File::Spec->devnull; 11 | my $DEBUG=1; 12 | 13 | # be cautious: run this only on systems I have tested it on 14 | my %os_ok=( linux => 1, solaris => 1, darwin => 1, MSWin32 => 1); 15 | if( !$os_ok{$^O}) { print "1..1\nok 1\n"; warn "skipping, test runs only on some OSs\n"; exit; } 16 | 17 | if( $] < 5.006) { print "1..1\nok 1\n"; warn "skipping, xml_merge runs only on perl 5.6 and later\n"; exit; } 18 | 19 | print "1..13\n"; 20 | 21 | my $perl = used_perl(); 22 | my $xml_split = File::Spec->catfile( "tools", "xml_split", "xml_split"); 23 | my $xml_merge = File::Spec->catfile( "tools", "xml_merge", "xml_merge"); 24 | 25 | sys_ok( "$perl -c $xml_split", "xml_split compilation"); 26 | sys_ok( "$perl -c $xml_merge", "xml_merge compilation"); 27 | 28 | my $xml= q{} . join( "\n ", map { elt( $_) } (1..10)) . qq{\n}; 29 | my $xml_file= "test_xml_split_g.xml"; 30 | spit( $xml_file => $xml); 31 | 32 | systemq( "$perl $xml_split -g 3 -n 3 $xml_file"); 33 | my $main_file= "test_xml_split_g-000.xml"; 34 | my @files= map { sprintf( "test_xml_split_g-%03d.xml", $_) } (1..4); 35 | foreach ( $main_file, @files) { ok( -f $_, "created $_"); } 36 | 37 | is_like( slurp( "test_xml_split_g-000.xml"), q{} . join( '', map { ""} @files) . q{}, 38 | "main file content"); 39 | 40 | is_like( slurp( "test_xml_split_g-001.xml"), sub_file( 1..3), "test_xml_split_g-001.xml content"); 41 | is_like( slurp( "test_xml_split_g-002.xml"), sub_file( 4..6), "test_xml_split_g-002.xml content"); 42 | is_like( slurp( "test_xml_split_g-003.xml"), sub_file( 7..9), "test_xml_split_g-003.xml content"); 43 | is_like( slurp( "test_xml_split_g-004.xml"), sub_file( 10), "test_xml_split_g-004.xml content"); 44 | 45 | unlink $xml_file; 46 | 47 | systemq( "$perl $xml_merge $main_file > $xml_file"); 48 | 49 | is_like( slurp( $xml_file), $xml, "merge result"); 50 | 51 | unlink $xml_file, $main_file, @files; 52 | 53 | sub sub_file 54 | { my @elt_nb= @_; 55 | return q{} 56 | . join( '', map { elt( $_)} @elt_nb) 57 | . q{}; 58 | } 59 | 60 | sub elt 61 | { my( $nb)= @_; 62 | return qq{element $nb}; 63 | } 64 | 65 | sub systemq 66 | { warn "$_[0]\n" if( !$DEBUG); 67 | system $_[0]; 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /parse_random_files: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Bug in XML::Twig? 4 | # 5 | 6 | 7 | use strict; 8 | use warnings; 9 | 10 | use lib "lib"; 11 | use XML::Twig::XPath; 12 | 13 | use Getopt::Std; 14 | my %opt; 15 | getopts( 'dn:s:S:', \%opt); # -d uses dispose 16 | # -n number of iterations (default 5) 17 | # -s set the rng seed 18 | # -S 1-10 size of the individual size default 8 19 | 20 | my $f_xml = "to_parse.xml"; 21 | my $prog = $0; 22 | 23 | my $nb= $opt{n} || 5; 24 | srand( $opt{s}) if $opt{s}; 25 | 26 | my $fsize= $opt{S} || 8; 27 | if( $fsize < 1 || $fsize > 10) { die "out-of-bounds value for -S option, must be 1-10\n"; } 28 | 29 | sub mem 30 | { 31 | my $ps = ($^O eq "cygwin") ? "procps" : "ps"; ## "procps" in cygwin 32 | my $size= `$ps aux | grep $prog | grep -v grep | grep -v gvim | perl -l -n -a -e'print \$F[5]'`; 33 | return formated( $size); 34 | } 35 | 36 | sub say 37 | { 38 | print scalar localtime(), ' | ', sprintf( "%-45s", @_), " : ", mem(), "\n"; 39 | } 40 | 41 | 42 | say "start"; 43 | 44 | foreach (1..$nb) 45 | { my $size= gen_random_files( $f_xml, $fsize); 46 | my $atwig = XML::Twig::XPath->new(); 47 | $atwig->safe_parsefile($f_xml) 48 | or die "can't load xml"; 49 | # use XPath searches to check for leakage 50 | my @hits_att = $atwig->findnodes( '/doc/line/hit[@att="abar"]'); 51 | my @hits_text = $atwig->findnodes( 'doc/line/hit[text()="efoo"]'); 52 | 53 | say sprintf( "run %3d (%s l) (hits: %6d - %6d)", $_, $size, scalar( @hits_att), scalar( @hits_text)); 54 | 55 | if( $opt{d}) 56 | { 57 | $atwig->dispose(); 58 | #say "dispose"; 59 | } 60 | } 61 | 62 | say "end"; 63 | 64 | 65 | sub gen_random_files 66 | { my( $file)= @_; 67 | my $size= int( 2**(rand($fsize+5)+5) + rand( 1000)) ; 68 | open( my $out, '>', $file) or die "cannot create $file: $!"; 69 | print {$out} "\n"; 70 | foreach my $l (1..$size) 71 | { print {$out} qq{ lorem ipsus whatever (clever latin stuff) no $l}; 72 | foreach my $m ( qw(foo bar baz)) { print {$out} qq{$m $le$m} if rand(2) > 1; } 73 | print {$out} qq{\n}; 74 | } 75 | print {$out} qq{\n}; 76 | close $out; 77 | return formated( $size); 78 | } 79 | 80 | sub formated 81 | { my( $nb)= shift; 82 | chomp $nb; 83 | $nb=~ s{(\d?\d?\d)(\d\d\d)(\d\d\d)$}{$1 $2 $3}; 84 | $nb=~ s{(\d?\d?\d)(\d\d\d)$}{$1 $2}; 85 | $nb= sprintf "%9s", $nb; 86 | return $nb; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /t/test_mark.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | 4 | # test the mark method 5 | 6 | use strict; 7 | use Carp; 8 | 9 | use File::Spec; 10 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 11 | use tools; 12 | 13 | #$|=1; 14 | my $DEBUG=0; 15 | 16 | use XML::Twig; 17 | 18 | my $perl= $]; 19 | 20 | my @data= map { chomp; [split /\t+/] } ; 21 | 22 | my $TMAX= 2 * @data; 23 | print "1..$TMAX\n"; 24 | 25 | foreach my $test (@data) 26 | { my( $doc, $regexp, $elts, $hits, $result)= @$test; 27 | (my $quoted_elts= $elts)=~ s{(\w+)}{'$1'}g; 28 | my @elts= eval( "($quoted_elts)"); 29 | my $t= XML::Twig->new->parse( $doc); 30 | my $root= $t->root; 31 | my @hits= $root->mark( $regexp, @elts); 32 | is( $t->sprint, $result, "mark( /$regexp/, $quoted_elts) on $doc"); 33 | is( scalar @hits, $hits, 'nb hits'); 34 | } 35 | 36 | 37 | exit 0; 38 | 39 | # doc regexp elts hits result 40 | __DATA__ 41 | text X (X) s 1 text X 42 | text X X s 1 text 43 | text X s 0 text 44 | text (X) s 0 text 45 | text X X s 1 text 46 | text X (X) s 1 text X 47 | text X \s*X\s* s 1 text 48 | text X \s*(X)\s* s 1 textX 49 | text X (\s*X\s*) s 1 text X 50 | text X text X s 1 text text 51 | text X text (X) s 1 text X text 52 | text X text \s*X\s* s 1 texttext 53 | text X text \s*(X)\s* s 1 textXtext 54 | text X text (\s*X\s*) s 1 text X text 55 | text XX X s 2 text 56 | text XX (X) s 2 text XX 57 | text X X X s 2 text 58 | text X X (X) s 2 text X X 59 | text XX text X s 2 text text 60 | text XX text (X) s 2 text XX text 61 | text XY text Y text X ([XY]+) s 3 text XY text Y text X 62 | text X X s, {a => 1} 1 text 63 | text X (X) s, {a => 1, b => 2} 1 text X 64 | text X1Y2 text X0 Y0X3Y4 text X X(\d)Y(\d) s 4 text 12 text X0 Y034 text X 65 | -------------------------------------------------------------------------------- /t/test2.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use File::Spec; 6 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 7 | use tools; 8 | 9 | # This tests the doctype and DTD access functions 10 | 11 | $|=1; 12 | 13 | use XML::Twig; 14 | use Cwd; 15 | 16 | $0 =~ s!\\!/!g; 17 | my ($DIR,$PROG) = $0 =~ m=^(.*/)?([^/]+)$=; 18 | $DIR =~ s=/$== || chop($DIR = cwd()); 19 | 20 | chdir $DIR; 21 | 22 | my $i=0; 23 | my $failed=0; 24 | 25 | my $TMAX=15; # don't forget to update! 26 | 27 | print "1..$TMAX\n"; 28 | 29 | # test twig creation 30 | my $t= new XML::Twig(); 31 | ok( $t, 'twig creation'); 32 | 33 | # first test an internal DTD 34 | 35 | my $in_file= "test2_1.xml"; 36 | 37 | my $res_file= "test2_1.res"; 38 | my $exp_file= "test2_1.exp"; 39 | 40 | # test parse no dtd info required 41 | $t->parsefile( $in_file, ErrorContext=>2); 42 | ok( $t, 'parse'); 43 | 44 | open( RES, ">$res_file") or die "cannot open $res_file:$!"; 45 | $t->print( \*RES); 46 | close RES; 47 | ok( $res_file, $exp_file, "flush"); 48 | 49 | $res_file= 'test2_2.res'; 50 | $exp_file= 'test2_2.exp'; 51 | open( RES, ">$res_file") or die "cannot open $res_file:$!"; 52 | $t->print( \*RES, Update_DTD => 1); 53 | close RES; 54 | ok( $res_file, $exp_file, "flush"); 55 | 56 | $t= new XML::Twig(); 57 | ok( $t, 'twig creation'); 58 | 59 | $in_file= "test2_2.xml"; 60 | $res_file= "test2_3.res"; 61 | $exp_file= "test2_3.exp"; 62 | 63 | $t->parsefile( $in_file, ErrorContext=>2); 64 | ok( $t, 'parse'); 65 | open( RES, ">$res_file") or die "cannot open $res_file:$!"; 66 | 67 | my $e2=new XML::Twig::Entity( 'e2', 'entity2'); 68 | my $entity_list= $t->entity_list; 69 | $entity_list->add( $e2); 70 | 71 | my $e3=new XML::Twig::Entity( 'e3', undef, 'pic.jpeg', 'JPEG'); 72 | $entity_list= $t->entity_list; 73 | $entity_list->add( $e3); 74 | 75 | $t->print( \*RES, Update_DTD => 1); 76 | close RES; 77 | 78 | ok( $res_file, $exp_file, "flush"); 79 | 80 | my $dtd= $t->dtd; 81 | ok( !$dtd, 'dtd exits'); 82 | 83 | $t= new XML::Twig(LoadDTD=>1); 84 | ok( $t, 'twig creation'); 85 | $t->parsefile( $in_file, ErrorContext=>2, ); 86 | 87 | $dtd= $t->dtd; 88 | ok( $dtd, 'dtd not found'); 89 | 90 | my @model= sort keys %{$dtd->{model}}; 91 | stest( stringify( @model), 'doc:intro:note:para:section:title', 'element list'); 92 | 93 | stest( $t->model( 'title'), '(#PCDATA)', 'title model'); 94 | mtest( $t->model( 'section'), '\(intro\?,\s*title,\s*\(para|note\)+\)', 'section model'); 95 | stest( $t->dtd->{att}->{section}->{id}->{type}, 'ID', 'section id type'); 96 | stest( $t->dtd->{att}->{section}->{id}->{default}, '#IMPLIED', 'section id default'); 97 | exit 0; 98 | 99 | 100 | -------------------------------------------------------------------------------- /t/test_keep_atts_order.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use File::Spec; 5 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 6 | use tools; 7 | 8 | 9 | use XML::Twig; 10 | 11 | 12 | { 13 | if( eval 'require Tie::IxHash') 14 | { import Tie::IxHash; 15 | print "1..7\n"; 16 | } 17 | else 18 | { warn( "Tie::IxHash not available, option keep_atts_order not allowed\n"); 19 | print "1..1\nok 1\n"; 20 | exit 0; 21 | } 22 | 23 | my $nb_elt=10; 24 | my $doc= gen_doc( $nb_elt); 25 | 26 | my $result= XML::Twig->new( pretty_print => 'indented')->parse( $doc)->sprint; 27 | isnt( $result, $doc, "keep_atts_order => 0 (first try)"); 28 | 29 | $result= XML::Twig->new( keep_atts_order => 1, pretty_print => 'indented')->parse( $doc)->sprint; 30 | is( $result, $doc, "keep_atts_order => 1 (first try)"); 31 | 32 | $result= XML::Twig->new( pretty_print => 'indented')->parse( $doc)->sprint; 33 | isnt( $result, $doc, "keep_atts_order => 0 (second try)"); 34 | 35 | $result= XML::Twig->new( keep_atts_order => 1, pretty_print => 'indented')->parse( $doc)->sprint; 36 | is( $result, $doc, "keep_atts_order => 1 (second try)"); 37 | 38 | $result= XML::Twig->new( keep_atts_order => 1, keep_encoding => 1, pretty_print => 'indented') 39 | ->parse( $doc)->sprint; 40 | is( $result, $doc, "keep_atts_order => 1, keep_encoding => 1 (first time)"); 41 | 42 | $result= XML::Twig->new( keep_encoding => 1, pretty_print => 'indented'); 43 | 44 | $result= XML::Twig->new( keep_atts_order => 1, keep_encoding => 1, pretty_print => 'indented') 45 | ->parse( $doc)->sprint; 46 | is( $result, $doc, "keep_atts_order => 1, keep_encoding => 1 (second time)"); 47 | 48 | $result= XML::Twig->new( keep_encoding => 1, pretty_print => 'indented') 49 | ->parse( $doc)->sprint; 50 | isnt( $result, $doc, " keep_encoding => 1 (second time)"); 51 | 52 | }; 53 | 54 | exit 0; 55 | 56 | sub gen_doc 57 | { my( $nb_elt)= @_; 58 | my $doc= "\n"; 59 | 60 | foreach (1..$nb_elt) 61 | { $doc .= " $_ + 1 } (0..4) ; 67 | 68 | while( my( $att, $value)= each %atts) 69 | { $doc .= qq{ $att="$value"}; } 70 | 71 | $doc .= "/>\n"; 72 | } 73 | $doc .= "\n"; 74 | return $doc; 75 | } 76 | 77 | sub randomize 78 | { my @list= @_; 79 | my $n= @list; 80 | foreach (1..10) 81 | { my $i= int rand( $n); 82 | my $j= int rand( $n); 83 | ($list[$i], $list[$j])=($list[$j], $list[$i]) 84 | } 85 | return @list; 86 | } 87 | -------------------------------------------------------------------------------- /t/test_3_35.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use Carp; 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | 10 | $|=1; 11 | my $DEBUG=0; 12 | 13 | use XML::Twig; 14 | 15 | my $TMAX=11; 16 | print "1..$TMAX\n"; 17 | 18 | # escape_gt option 19 | { 20 | is( XML::Twig->parse( '')->root->insert_new_elt( '#COMMENT' => '- -- -')->twig->sprint, 21 | '', 'comment escaping'); 22 | } 23 | 24 | { my $t= XML::Twig->parse( 'foobarbazfoobarbaz2foobar2'); 25 | $t->root->cut_descendants( 'e[@a="c"]'); 26 | is( $t->sprint, 'bazfoobarbaz2', 'cut_descendants'); 27 | } 28 | 29 | { my $t=XML::Twig->new( pretty_print => 'none')->parse( ''); 30 | is( $t->root->_pretty_print, 0, '_pretty_print'); 31 | $t->set_pretty_print( 'indented'); 32 | is( $t->root->_pretty_print, 3, '_pretty_print'); 33 | } 34 | 35 | # additional tests to increase coverage 36 | { is( XML::Twig->parse( no_expand => 1, q{]>&foo;})->root->sprint, "&foo;\n", 'external entities with no_expand'); 37 | } 38 | 39 | { my $doc= q{fi4}; 40 | my $tmp = 'tmp-t35'; 41 | open( my $fh, '>', $tmp ); 42 | my $t= XML::Twig->new( twig_handlers => { e => sub { $_->flush( $fh); }, 43 | g => sub { is( $_[0]->elt_id( 'i4')->text, 'fi4', 'elt_id, id exists'); 44 | nok( $_[0]->elt_id( 'i3'), 'elt_id, id flushed'); 45 | }, 46 | }, 47 | ) 48 | ->parse( $doc); 49 | close $fh; 50 | is(slurp_trimmed( $tmp ), $doc, 'flush on element still outputs the entire document'); 51 | } 52 | 53 | { my $xpath=''; 54 | XML::Twig->parse( map_xmlns => { "http://foo.com" => 'bar' }, 55 | twig_handlers => { "bar:e" => sub { $xpath= $_[0]->path( $_->gi);}, }, 56 | q{} 57 | ); 58 | is( $xpath, '/bar:d/bar:e'); 59 | XML::Twig->parse( map_xmlns => { "http://foo.com" => 'bar' }, 60 | twig_handlers => { "bar:e" => sub { $xpath= $_[0]->path( $_->local_name);}, }, 61 | q{} 62 | ); 63 | is( $xpath, '/bar:d/bar:e'); 64 | } 65 | 66 | { my $t=XML::Twig->parse( pretty_print => 'none', ''); 67 | $t->first_elt( 'e3')->replace( $t->first_elt( 'e1')); 68 | is( $t->sprint, '', 'replace called on an element that has not been cut yet'); 69 | } 70 | 1; 71 | -------------------------------------------------------------------------------- /t/test_with_lwp.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use Carp; 5 | 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | 10 | 11 | $|=1; 12 | 13 | use XML::Twig; 14 | 15 | eval { require LWP; }; 16 | if( $@) { import LWP; print "1..1\nok 1\n"; warn "skipping, LWP not available\n"; exit } 17 | 18 | # skip on Win32, it looks like we have a problem there (named pipes?) 19 | if( ($^O eq "MSWin32") && ($]<5.008) ) { print "1..1\nok 1\n"; warn "skipping, *parseurl methods not available on Windows with perl < 5.8.0\n"; exit } 20 | 21 | if( perl_io_layer_used()) 22 | { print "1..1\nok 1\n"; 23 | warn "cannot test parseurl when UTF8 perIO layer used (due to PERL_UNICODE or -C option used)\n"; 24 | exit; 25 | } 26 | 27 | my $TMAX=13; 28 | 29 | chdir 't'; 30 | 31 | print "1..$TMAX\n"; 32 | 33 | { my $t= XML::Twig->new->parseurl( 'file:test_with_lwp.xml', LWP::UserAgent->new); 34 | is( $t->sprint, 'text', "parseurl"); 35 | } 36 | 37 | { 38 | my $t= XML::Twig->new->parseurl( 'file:test_with_lwp.xml'); 39 | is( $t->sprint, 'text', "parseurl"); 40 | } 41 | 42 | { 43 | my $t= XML::Twig->new->safe_parseurl( 'file:test_with_lwp.xml'); 44 | is( $t->sprint, 'text', "parseurl"); 45 | } 46 | 47 | { 48 | warn "\n\n### warning is normal here ###\n\n"; 49 | my $t=0; 50 | if ($^O ne 'VMS') 51 | { # On VMS we get '%SYSTEM-F-ABORT, abort' and an exit when a file does not exist 52 | # Behaviour is probably different on VMS due to it not having 'fork' to do the 53 | # LWP::UserAgent request and (safe) parse of that request not happening in a child process. 54 | $t = XML::Twig->new->safe_parseurl( 'file:test_with_lwp_no_file.xml'); 55 | ok( !$t, "no file"); 56 | matches( $@, '^\s*(no element found|Ran out of memory for input buffer)', "no file, error message"); 57 | } 58 | else 59 | { skip( 2 => "running on VMS, cannot test error message for non-existing file"); } 60 | } 61 | 62 | { 63 | my $t= XML::Twig->new->safe_parseurl( 'file:test_with_lwp_not_wf.xml'); 64 | ok( !$t, "not well-formed"); 65 | matches( $@, '^\s*mismatched tag', "not well-formed, error message"); 66 | } 67 | 68 | { 69 | my $t= XML::Twig->new->parsefile( 'test_with_lwp.xml'); 70 | is( $t->sprint, 'text', "parseurl"); 71 | } 72 | 73 | { 74 | my $t= XML::Twig->new->safe_parsefile( 'test_with_lwp.xml'); 75 | is( $t->sprint, 'text', "parseurl"); 76 | } 77 | 78 | { 79 | my $t= XML::Twig->new->safe_parsefile( 'test_with_lwp_no_file.xml'); 80 | ok( !$t, "no file"); 81 | matches( $@, '^\s*Couldn', "no file, error message"); 82 | } 83 | 84 | { 85 | my $t= XML::Twig->new->safe_parsefile( 'test_with_lwp_not_wf.xml'); 86 | ok( !$t, "not well-formed"); 87 | matches( $@, '^\s*mismatched tag', "not well-formed, error message"); 88 | } 89 | 90 | exit 0; 91 | 92 | -------------------------------------------------------------------------------- /t/test_ignore_elts.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use XML::Twig; 5 | 6 | $|=1; 7 | 8 | my $TMAX=1; # do not forget to update! 9 | print "1..$TMAX\n"; 10 | 11 | my $doc= read_data(); 12 | 13 | my $t= XML::Twig->new( ignore_elts => { ignore => 1 }, 14 | keep_spaces => 1, 15 | ); 16 | my $result_file= "test_ignore_elt.res1"; 17 | open( RESULT, ">$result_file") or die "cannot create $result_file: $!"; 18 | select RESULT; 19 | $t->parse( $doc); 20 | $t->print; 21 | select STDOUT; 22 | close RESULT; 23 | check_result( $result_file, 1); 24 | 25 | exit 0; 26 | 27 | # Not yet implemented 28 | 29 | # test 2 30 | $doc= read_data(); 31 | 32 | $t= XML::Twig->new( ignore_elts => { ignore => 'print' }, 33 | twig_handlers => { elt => sub { $_->print; } }, 34 | keep_spaces => 1, 35 | ); 36 | $result_file= "test_ignore_elt.res2"; 37 | open( RESULT, ">$result_file") or die "cannot create $result_file: $!"; 38 | select RESULT; 39 | $t->parse( $doc); 40 | $t->print; 41 | select STDOUT; 42 | close RESULT; 43 | check_result( $result_file, 2); 44 | 45 | 46 | 47 | sub read_data 48 | { local $/="\n\n"; 49 | my $data= ; 50 | $data=~ s{^\s*#.*\n}{}m; # get rid of comments 51 | $data=~ s{\s*$}{}s; # remove trailing spaces (and \n) 52 | $data=~ s{(^|\n)\s*(\n|$)}{}g; # remove empty lines 53 | return $data; 54 | }; 55 | 56 | 57 | sub check_result 58 | { my( $result_file, $test_no)= @_; 59 | # now check result 60 | my $expected_result= read_data(); 61 | my $result= read_result( $result_file); 62 | if( $result eq $expected_result) 63 | { print "ok $test_no\n"; } 64 | else 65 | { print "not ok $test_no\n"; 66 | print STDERR "\ntest $test_no:\n", 67 | "expected: \n$expected_result\n", 68 | "real: \n$result\n"; 69 | } 70 | } 71 | 72 | 73 | sub read_result 74 | { my $file= shift; 75 | local $/="\n"; 76 | open( RESULT, "<$file") or die "cannot read $file: $!"; 77 | my @result= grep {m/\S/} ; 78 | close RESULT; 79 | unlink $file; 80 | return join '', @result; 81 | } 82 | 83 | 84 | 85 | __DATA__ 86 | # doc 1 87 | 88 | text 89 | 90 | 91 | text 92 | 93 | 94 | 95 | # expected result 1 96 | 97 | 98 | 99 | 100 | 101 | 102 | #doc 2 103 | 104 | text 105 | 106 | 107 | 108 | text 109 | 110 | 111 | # expected result 2 112 | text 113 | 114 | 115 | 116 | text 117 | -------------------------------------------------------------------------------- /t/test_3_39.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use Carp; 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | 10 | $|=1; 11 | my $DEBUG=0; 12 | 13 | use XML::Twig; 14 | 15 | my $TMAX=12; 16 | print "1..$TMAX\n"; 17 | 18 | { 19 | my $doc='foo bar fooo baz'; 20 | 21 | my $t= XML::Twig->parse( $doc); 22 | $t->root->split( '(fo+)', e => { att => '$1' } ); 23 | is( $t->sprint, 'foo bar fooo baz', 'split, with $1 on attribute value'); 24 | 25 | $t= XML::Twig->parse( $doc); 26 | $t->root->split( '(fo+)', e => { '$1' => 'v$1' } ); 27 | is( $t->sprint, 'foo bar fooo baz', 'split, with $1 on attribute name and value'); 28 | 29 | $t= XML::Twig->parse( $doc); 30 | $t->root->split( '(fo+)', '$1' ); 31 | is( $t->sprint, 'foo bar fooo baz', 'split, with $1 on tag name'); 32 | 33 | 34 | $t= XML::Twig->parse( $doc); 35 | $t->root->split( '(foo+)', '$1', '' ); 36 | is( $t->sprint, 'foo bar fooo baz', 'split, with $1 on tag name'); 37 | 38 | $t= XML::Twig->parse( $doc); 39 | $t->root->split( '(fo+)(.*?)(a[rz])', x => { class => 'f' }, '', a => { class => 'x' }); 40 | is( $t->sprint, 'foo bar fooo baz', 'split, checking that it works with non capturing grouping'); 41 | 42 | $t= XML::Twig->parse( $doc); 43 | $t->root->split( '(fo+)(.*?)(a[rz])', x => { class => '$1' }, '', a => { class => '$3' }); 44 | is( $t->sprint, 'foo bar fooo baz', 'split, with $1 and $3 on att value'); 45 | 46 | } 47 | 48 | { my $t= XML::Twig->parse( 'e1e2'); 49 | is( join( '-', $t->findvalues( '//e')), 'e1-e2', 'findvalues'); 50 | } 51 | 52 | { my $html='

boo

'; 53 | 54 | my $well_formed = qq{$html}; 55 | my $short_doctype = qq{$html}; 56 | 57 | my $t= XML::Twig->new->parse( $well_formed); 58 | is_like( $t->sprint, $well_formed, 'valid xhtml'); 59 | if( _use( 'HTML::TreeBuilder')) 60 | { my $th= XML::Twig->new->parse_html( $well_formed); 61 | is_like( $t->sprint, $well_formed, 'valid xhtml (parsed as html)'); 62 | 63 | my $t3= XML::Twig->new->parse_html( $short_doctype); 64 | is_like( $t3->sprint, $html, 'xhtml without SYSTEM in DOCTYPE (parsed as html, no DOCTYPE output)'); 65 | 66 | my $t4= XML::Twig->new( output_html_doctype => 1)->parse_html( $short_doctype); 67 | is_like( $t4->sprint, $well_formed, 'xhtml without SYSTEM in DOCTYPE (parsed as html, with proper DOCTYPE output)'); 68 | } 69 | else 70 | { skip( 3); } 71 | 72 | my $t2= XML::Twig->new->safe_parse( $short_doctype); 73 | nok( $t2, 'xhtml without SYSTEM in DOCTYPE'); 74 | 75 | 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /t/xmlxpath_xpath_cond.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use File::Spec; 5 | use lib File::Spec->catdir(File::Spec->curdir,'t'); 6 | use tools; 7 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 8 | 9 | 10 | $|=1; 11 | 12 | my $t= XML::Twig::XPath->new; 13 | $t->parse( 14 | ' 15 | elt 1 16 | elt 2 17 | 18 | elt 3 19 | 20 | 21 | 2 22 | 3 23 | 24 | '); 25 | 26 | my @data= grep { !/^##/ && m{\S} } ; 27 | 28 | my @exp; 29 | my %result; 30 | 31 | foreach( @data) 32 | { chomp; 33 | my ($exp, $id_list) = split /\s*=>\s*/ ; 34 | $result{$exp}= $id_list; 35 | push @exp, $exp; 36 | } 37 | 38 | my $nb_tests= 2 + keys %result; 39 | print "1..$nb_tests\n"; 40 | 41 | my $i=1; 42 | 43 | foreach my $exp ( @exp) 44 | { my $expected_result= $result{$exp}; 45 | my @result= $t->findnodes( $exp); 46 | my $result; 47 | if( @result) 48 | { $result= join ' ', map { $_->id } @result; } 49 | else 50 | { $result= 'none'; } 51 | 52 | if( $result eq $expected_result) 53 | { print "ok $i\n"; } 54 | else 55 | { print "nok $i\n"; 56 | print STDERR "$exp: expected $expected_result - real $result\n"; 57 | } 58 | $i++; 59 | } 60 | 61 | my $exp= '//* |//@* | /'; 62 | my @result= $t->findnodes( $exp); 63 | my @elts= $t->descendants( '#ELT'); 64 | 65 | # first check the number of results 66 | my $result= @result; 67 | my $nb_atts=0; 68 | foreach (@elts) { $nb_atts+= $_->att_nb; } 69 | my $expected_result= scalar @elts + $nb_atts + 1; 70 | 71 | if( $result == $expected_result) 72 | { print "ok $i\n"; } 73 | else 74 | { print "nok $i\n"; 75 | print STDERR "$exp: expected $expected_result - real $result\n"; 76 | } 77 | $i++; 78 | 79 | # then check the results (to make sure they are in hte right order) 80 | my @expected_results; 81 | push @expected_results, "XML::Twig::XPath '" . $t->sprint ."'"; 82 | foreach my $elt (@elts) 83 | { push @expected_results, ref( $elt) . " '" . $elt->sprint . "'" ; 84 | foreach my $att ($elt->att_names) 85 | { push @expected_results, qq{XML::Twig::XPath::Attribute '$att="} . $elt->att( $att) . q{"'} ; } 86 | } 87 | $expected_result= join( "\n ", @expected_results); 88 | $result= join( "\n ", map { ref( $_) . " '" . $_->toString ."'" } @result); 89 | if( $result eq $expected_result) 90 | { print "ok $i\n"; } 91 | else 92 | { print "nok $i\n"; 93 | print STDERR "$exp:\nexpected: $expected_result\n\nreal : $result\n"; 94 | } 95 | $i++; 96 | 97 | exit 0; 98 | 99 | __DATA__ 100 | /elt => none 101 | //elt => elt-1 elt-2 elt-3 102 | /doc/elt => elt-1 elt-2 103 | /doc/elt[ last()] => elt-2 104 | //elt[@id='elt-1'] => elt-1 105 | //elt[@id="elt-1"] | //elt[@id="elt-2"] | //elt[@id="elt-3"] => elt-1 elt-2 elt-3 106 | //elt[@id="elt-1" or @id="elt-2" or @id="elt-3"] => elt-1 elt-2 elt-3 107 | //elt2[@att_int > 2] => elt2-4 108 | /doc/elt2[ last()]/* => elt2-3 elt2-4 109 | //*[@id="elt2-2"] => elt2-2 110 | /doc/elt2[./elt[@id="elt-3"]] => elt2-1 111 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | NAME 2 | 3 | XML::Twig - Tree interface to XML documents allowing processing chunk 4 | by chunk of huge documents. 5 | 6 | 7 | SUMMARY (see perldoc XML::Twig for full details) 8 | 9 | XML::Twig is (yet another!) XML transformation module. 10 | 11 | Its strong points: can be used to process huge documents while still 12 | being in tree mode; not bound by DOM or SAX, so it is very perlish and 13 | offers a very comprehensive set of methods; simple to use; DWIMs as 14 | much as possible 15 | 16 | What it doesn't offer: full SAX support (it can export SAX, but only 17 | reads XML), full XPath support (unless you use XML::Twig::XPath), nor 18 | DOM support. 19 | 20 | Other drawbacks: it is a big module, and with over 500 methods available 21 | it can be a bit overwhelming. A good starting point is the tutorial at 22 | http://xmltwig.org/xmltwig/tutorial/index.html. In fact the whole 23 | XML::Twig page at http://xmltwig.org/xmltwig/ has plenty of information 24 | to get you started with XML::Twig 25 | 26 | TOOLS 27 | 28 | XML::Twig comes with a few tools built on top of it: 29 | 30 | xml_pp XML pretty printer 31 | xml_grep XML grep - grep XML files using XML::Twig's subset of XPath 32 | xml_split split big XML files 33 | xml_merge merge back files created by xml_split 34 | xml_spellcheck spellcheck XML files skipping tags 35 | 36 | Running perl Makefile.PL will prompt you for each tool installation. 37 | perl Makefile.PL -y will install all of the tools without prompt 38 | perl Makefile.PL -n will skip the installation of the tools 39 | 40 | 41 | SYNOPSYS 42 | 43 | single-tree mode 44 | my $t= XML::Twig->new(); 45 | $t->parsefile( 'doc.xml'); 46 | $t->print; 47 | 48 | chunk mode 49 | # print the document, at most one full section is loaded in memory 50 | my $t= XML::Twig->new( twig_handlers => { section => \&flush}); 51 | $t->parsefile( 'doc.xml'); 52 | $t->flush; 53 | sub flush { (my $twig, $section)= @_; $twig->flush; } 54 | 55 | sub-tree mode 56 | # print all section title's in the document, 57 | # all other elements are ignored (and not stored) 58 | my $t= XML::Twig->new( 59 | twig_roots => { 'section/title' => sub { $_->print, "\n" } } 60 | ); 61 | $t->parsefile( 'doc.xml'); 62 | 63 | INSTALLATION 64 | 65 | perl Makefile.PL 66 | make 67 | make test 68 | make install 69 | 70 | DEPENDENCIES 71 | 72 | XML::Twig needs XML::Parser (and the expat library) installed 73 | 74 | Modules that can enhance XML::Twig are: 75 | 76 | Scalar::Util or WeakRef 77 | to avoid memory leaks 78 | Tie::IxHash 79 | to use the keep_atts_order option 80 | XML::XPathEngine 81 | to use XML::Twig::XPath 82 | LWP 83 | to use parseurl 84 | HTML::Entities 85 | to use the html_encode filter 86 | HTML::TreeBuilder 87 | to process HTML instead of XML 88 | 89 | CHANGES 90 | 91 | See the Changes file 92 | 93 | AUTHOR 94 | 95 | Michel Rodriguez (mirod@cpan.org) 96 | The Twig page is at http://www.xmltwig.org/xmltwig 97 | git project repository: http://github.com/mirod/xmltwig 98 | See the XML::Twig tutorial at http://www.xmltwig.org/xmltwig/tutorial/index.html 99 | 100 | COPYRIGHT 101 | 102 | Copyright (c) 1999-2025, Michel Rodriguez. All Rights Reserved. 103 | This library is free software; you can redistribute it and/or modify 104 | it under the same terms as Perl itself. 105 | -------------------------------------------------------------------------------- /t/test_wrapped.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use strict; 6 | use Carp; 7 | use File::Spec; 8 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 9 | use tools; 10 | 11 | $|=1; 12 | my $DEBUG=0; 13 | 14 | use XML::Twig; 15 | 16 | 17 | my $TMAX=13; 18 | print "1..$TMAX\n"; 19 | 20 | unless( XML::Twig::_use( 'Text::Wrap')) { print "1..1\nok 1\n"; warn "skipping: Text::Wrap not available\n"; exit; } 21 | 22 | while( my $doc= get_doc()) 23 | { my $result= XML::Twig->nparse( pretty_print => 'wrapped', $doc)->sprint; 24 | my $expected= get_doc(); 25 | foreach ($result, $expected) { s{ }{.}g; } 26 | is( $result, $expected, ''); 27 | } 28 | 29 | XML::Twig::Elt->set_wrap(0); 30 | is( XML::Twig::Elt->set_wrap(1), 0, "set_wrap - 1"); 31 | is( XML::Twig::Elt->set_wrap(1), 1, "set_wrap - 2"); 32 | is( XML::Twig::Elt->set_wrap(0), 1, "set_wrap - 3"); 33 | is( XML::Twig::Elt->set_wrap(0), 0, "set_wrap - 4"); 34 | 35 | is( XML::Twig::Elt::set_wrap(1), 0, "set_wrap - 5"); 36 | is( XML::Twig::Elt::set_wrap(1), 1, "set_wrap - 6"); 37 | is( XML::Twig::Elt::set_wrap(0), 1, "set_wrap - 7"); 38 | is( XML::Twig::Elt::set_wrap(0), 0, "set_wrap - 8"); 39 | 40 | sub get_doc 41 | { local $/="\n\n"; 42 | my $doc= ; 43 | if( $doc) 44 | { $doc=~ s{\n\n}{\n}; 45 | $doc=~ s/\{([^}]*)\}/$1/eeg; 46 | } 47 | return $doc; 48 | } 49 | 50 | 51 | __DATA__ 52 | {"foo" x 40} 53 | 54 | 55 | foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo 56 | foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo 57 | 58 | 59 | {"foo" x 80} 60 | 61 | 62 | foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo 63 | foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo 64 | ofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoof 65 | oofoofoofoofoofoofoofoofoofoofoo 66 | 67 | 68 |
{"foo" x 40}
69 | 70 | 71 |
72 | foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoof 73 | oofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo 74 |
75 |
76 | 77 | 78 | {"foo " x 40} 79 | {"bar " x 40} 80 | 81 | 82 | 83 | foo foo foo foo foo foo foo foo foo foo foo foo foo foo 84 | foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo 85 | foo foo foo foo foo foo foo foo 86 | bar bar bar bar bar bar bar bar bar bar bar bar bar bar 87 | bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar 88 | bar bar bar bar bar bar bar bar 89 | 90 | 91 | 92 | {"foo " x 40}{ "aaa" x 60}{ "foo "x20 } 93 | {"bar " x 40} 94 | 95 | 96 | 97 | foo foo foo foo foo foo foo foo foo foo foo foo foo foo 98 | foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo 99 | foo foo foo foo foo foo foo foo 100 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 101 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 102 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafoo foo foo foo foo foo foo foo 103 | foo foo foo foo foo foo foo foo foo foo foo foo 104 | bar bar bar bar bar bar bar bar bar bar bar bar bar bar 105 | bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar 106 | bar bar bar bar bar bar bar bar 107 | 108 | -------------------------------------------------------------------------------- /t/test_xpath_cond.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use XML::Twig; 5 | 6 | $|=1; 7 | 8 | my $t= XML::Twig->new; 9 | $t->parse( 10 | ' 11 | elt 1 12 | elt 2 13 | 14 | elt 3 15 | 16 | 17 | 2 18 | 3 19 | 20 | <:elt id=":elt">yep, that is a valid name 21 | '); 22 | 23 | my @data= grep { !/^##/ && m{\S} } ; 24 | 25 | my @exp; 26 | my %result; 27 | 28 | foreach( @data) 29 | { chomp; 30 | my ($exp, $id_list) = split /\s*=>\s*/ ; 31 | $id_list=~ s{\s+$}{}; 32 | $result{$exp}= $id_list; 33 | push @exp, $exp; 34 | } 35 | 36 | my $nb_tests= keys %result; 37 | print "1..$nb_tests\n"; 38 | 39 | my $i=1; 40 | 41 | foreach my $exp ( @exp) 42 | { my $expected_result= $result{$exp}; 43 | my @result= $t->get_xpath( $exp); 44 | my $result; 45 | if( @result) 46 | { $result= join ' ', map { $_->id || $_->gi } @result; } 47 | else 48 | { $result= 'none'; } 49 | 50 | if( $result eq $expected_result) 51 | { print "ok $i\n"; } 52 | else 53 | { print "not ok $i\n"; 54 | print STDERR "$exp: expected '$expected_result' - real '$result'\n"; 55 | } 56 | $i++; 57 | } 58 | 59 | exit 0; 60 | 61 | __DATA__ 62 | /elt => none 63 | /elt[@foo="bar"] => none 64 | /*[@foo="bar"] => none 65 | //*[@foo="bar"] => none 66 | /* => doc 67 | /*[@id="doc"] => doc 68 | //*[@id="doc"] => doc 69 | //elt => elt-1 elt-2 elt-3 70 | //*/elt => elt-1 elt-2 elt-3 71 | /doc/elt => elt-1 elt-2 72 | /*/elt => elt-1 elt-2 73 | /doc/elt[ last()] => elt-2 74 | /doc/*[ last()] => :elt 75 | //elt[@id='elt-1'] => elt-1 76 | //*[@id='elt-1'] => elt-1 77 | //[@id='elt-1'] => elt-1 78 | //elt[@id='elt-1' or @id='elt-2'] => elt-1 elt-2 79 | //elt[@id='elt-1' and @id='elt-2'] => none 80 | //elt[@id='elt-1' and @id!='elt-2'] => elt-1 81 | //elt[@id=~ /elt/] => elt-1 elt-2 elt-3 82 | //[@id='elt-1' or @id='elt-2'] => elt-1 elt-2 83 | //[@id='elt-1' and @id='elt-2'] => none 84 | //[@id='elt-1' and @id!='elt-2'] => elt-1 85 | //[@id=~ /elt/] => elt-1 elt-2 elt2-1 elt-3 elt2-2 elt2-3 elt2-4 :elt 86 | //*[@id='elt-1' or @id='elt-2'] => elt-1 elt-2 87 | //*[@id='elt-1' and @id='elt-2'] => none 88 | //*[@id='elt-1' and @id!='elt-2'] => elt-1 89 | //*[@id=~ /elt/] => elt-1 elt-2 elt2-1 elt-3 elt2-2 elt2-3 elt2-4 :elt 90 | //elt2[@att_int > 2] => elt2-4 91 | /doc/elt2[ last()]/* => elt2-3 elt2-4 92 | //*[@id=~/elt2/] => elt2-1 elt2-2 elt2-3 elt2-4 93 | /doc/*[@id=~/elt2/] => elt2-1 elt2-2 94 | /doc//*[@id=~/elt2/] => elt2-1 elt2-2 elt2-3 elt2-4 95 | //*[@id=~/elt2-[34]/] => elt2-3 elt2-4 96 | //*[@id!~/^elt/] => doc :elt 97 | //[@id=~/elt2-[34]/] => elt2-3 elt2-4 98 | //[@id!~/elt2-[34]/] => doc elt-1 elt-2 elt2-1 elt-3 elt2-2 :elt 99 | //elt2[@id=~/elt2-[34]/] => elt2-3 elt2-4 100 | //*[@id!~/elt2-[34]/] => doc elt-1 elt-2 elt2-1 elt-3 elt2-2 :elt 101 | //:elt => :elt 102 | //elt[string()="elt 1"] => elt-1 103 | //elt[string()=~/elt 1/] => elt-1 104 | //elt[string()=~/^elt 1/] => elt-1 105 | //*[string()="elt 1"] => elt-1 #PCDATA 106 | //*[string()=~/elt 1/] => doc elt-1 #PCDATA 107 | //*[string()=~/^elt 1/] => doc elt-1 #PCDATA 108 | //[string()="elt 1"] => elt-1 #PCDATA 109 | //[string()=~/elt 1/] => doc elt-1 #PCDATA 110 | //[string()=~/^elt 1/] => doc elt-1 #PCDATA 111 | //[string()="elt 2"] => elt-2 #PCDATA 112 | //[string()=~/elt 2/] => doc elt-2 #PCDATA 113 | //[string()=~/^elt 2/] => elt-2 #PCDATA 114 | -------------------------------------------------------------------------------- /t/test_3_24.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use strict; 6 | use Carp; 7 | use File::Spec; 8 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 9 | use tools; 10 | 11 | $|=1; 12 | my $DEBUG=0; 13 | 14 | use XML::Twig; 15 | 16 | my $TMAX=15; 17 | print "1..$TMAX\n"; 18 | 19 | { # adding comments or pi's before/after the root 20 | my $doc= XML::Twig->nparse( ''); 21 | my $xsl = XML::Twig::Elt->new('#PI'); 22 | $xsl->set_target('xml-stylesheet'); 23 | $xsl->set_data('type= "text/xsl" href="xsl_style.xsl"'); 24 | $xsl->paste( before => $doc->root); 25 | is( $doc->sprint, '', 26 | 'PI before the root' 27 | ); 28 | my $comment= XML::Twig::Elt->new( '#COMMENT'); 29 | $comment->set_comment( 'foo'); 30 | $comment->paste( before => $doc->root); 31 | 32 | is( $doc->sprint, '', 33 | 'Comment before the root' 34 | ); 35 | 36 | XML::Twig::Elt->new( '#COMMENT')->set_comment( 'bar')->paste( after => $doc->root); 37 | XML::Twig::Elt->new( '#PI')->set_target( 'foo')->set_data( 'bar')->paste( after => $doc->root); 38 | is( $doc->sprint, '', 39 | 'Pasting things after the root' 40 | ); 41 | 42 | } 43 | 44 | { # adding comments or pi's before/after the root 45 | my $doc= XML::Twig->nparse( ''); 46 | $doc->add_stylesheet( xsl => 'xsl_style.xsl'); 47 | is( $doc->sprint, '', 'add_stylesheet'); 48 | eval{ $doc->add_stylesheet( foo => 'xsl_style.xsl') }; 49 | matches( $@, q{^unsupported style sheet type 'foo'}, 'unsupported stylesheet type'); 50 | } 51 | 52 | { # creating a CDATA element 53 | my $elt1= XML::Twig::Elt->new( foo => { '#CDATA' => 1 }, '<&>'); 54 | is( $elt1->sprint, ']]>', "creating a CDATA element"); 55 | my $elt2= XML::Twig::Elt->new( foo => { '#CDATA' => 1, att => 'v1' }, '<&>'); 56 | is( $elt2->sprint, ']]>', "creating a CDATA element"); 57 | eval { my $elt3= XML::Twig::Elt->new( foo => { '#CDATA' => 1 }, "bar", $elt1); }; 58 | matches( $@, qr/^element #CDATA can only be created from text/, 59 | "error in creating CDATA element"); 60 | my $elt4= XML::Twig::Elt->new( foo => { '#CDATA' => 1 }, '<&>', 'bar'); 61 | is( $elt4->sprint, 'bar]]>', "creating a CDATA element (from list)"); 62 | 63 | } 64 | 65 | { # errors creating text/comment/pi elements 66 | eval { my $elt= XML::Twig::Elt->new( '#PCDATA', []); }; 67 | matches( $@, qr/^element #PCDATA can only be created from text/, "error in creating PCDATA element"); 68 | 69 | eval { my $elt= XML::Twig::Elt->new( '#COMMENT', "foo", []); }; 70 | matches( $@, qr/^element #COMMENT can only be created from text/, "error in creating COMMENT element"); 71 | 72 | eval { my $elt= XML::Twig::Elt->new( '#PI', "foo", [], "bah!"); }; 73 | matches( $@, qr/^element #PI can only be created from text/, "error in creating PI element"); 74 | 75 | } 76 | 77 | { # set_cdata on non CDATA element 78 | my $elt = XML::Twig::Elt->new("qux"); 79 | $elt->set_cdata("test this '<' & this '>'"); 80 | is( $elt->sprint, q{']]>}, "set_cdata on non CDATA element"); 81 | } 82 | 83 | { # set_comment on non comment element 84 | my $elt = XML::Twig::Elt->new(qux => "toto"); 85 | $elt->set_comment( " booh "); 86 | is( $elt->sprint, q{}, "set_comment on non comment element"); 87 | } 88 | 89 | { # set_pi on non pi element 90 | my $elt = XML::Twig::Elt->new(qux => "toto"); 91 | $elt->set_pi( ta => "tie ramisu"); 92 | is( $elt->sprint, q{}, "set_pi on non pi element"); 93 | } 94 | -------------------------------------------------------------------------------- /t/test_3_45.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use XML::Twig; 7 | use Test::More tests => 16; 8 | 9 | is( XML::Twig->new( keep_encoding => 1)->parse( q{})->sprint, q{}, "quote in att with keep_encoding"); 10 | 11 | # test CDATA sections in HTML escaping https://rt.cpan.org/Ticket/Display.html?id=86773 12 | my $html = <<'EOF'; 13 |
body
14 | 19 | EOF 20 | 21 | # module => XML::Twig->new options 22 | my %html_conv= ( 'HTML::TreeBuilder' => {}, 23 | 'HTML::Tidy' => { use_tidy => 1 }, 24 | ); 25 | foreach my $module ( sort keys %html_conv) 26 | { SKIP: 27 | { eval "use $module"; 28 | skip "$module not available", 3 if $@ ; 29 | 30 | my $parser= XML::Twig->new( %{$html_conv{$module}}); 31 | my $xml = $parser->safe_parse_html($html); 32 | print $@ if $@; 33 | 34 | my @cdata = $xml->get_xpath('//#CDATA'); 35 | ok(@cdata == 1, "1 CDATA section found (using $module)"); 36 | 37 | ok(((index $xml->sprint, "//]]>") >= 0), "end of cdata ok in doc (using $module)"); 38 | #diag "\n", $xml->sprint, "\n"; 39 | 40 | my @elts = $xml->get_xpath('//script'); 41 | 42 | foreach my $el (@elts) 43 | { #diag $el->sprint; 44 | ok(((index $el->sprint, "//]]>") >= 0), "end of cdata ok in script element (using $module)"); 45 | } 46 | } 47 | } 48 | 49 | # test & in HTML (RT #86633) 50 | my $html_with_amp='

Marco&company

'; 51 | my $expected_body= '

Marco&company

'; 52 | 53 | SKIP: 54 | { eval "use HTML::Tidy"; 55 | skip "HTML::Tidy not available", 1 if $@ ; 56 | my $parsert = XML::Twig->new(); 57 | my $html_tidy = $parsert->safe_parse_html( { use_tidy => 1 }, "

Marco&company

"); 58 | diag $@ if $@; 59 | is( $html_tidy->first_elt( 'body')->sprint, $expected_body, "& in text, converting html with use_tidy"); 60 | } 61 | 62 | SKIP: 63 | { eval "use HTML::TreeBuilder"; 64 | skip "HTML::TreeBuilder not available", 1 if $@ ; 65 | my $parserh= XML::Twig->new(); 66 | my $html = $parserh->safe_parse_html("

Marco&company

"); 67 | diag $@ if $@; 68 | is( $html->first_elt( 'body')->sprint , $expected_body, "& in text, converting html with treebuilder"); 69 | } 70 | 71 | is( XML::Twig::_unescape_cdata( '<tag att="foo&bar&baz">>></tag>'), '>>', '_unescape_cdata'); 72 | 73 | SKIP: 74 | { skip "safe_print_to_file method does not work on Windows", 6 if $^O =~ m{win}i; 75 | # testing safe_print_to_file 76 | my $tmp= "safe_print_to_file.xml"; 77 | my $doc= "foo"; 78 | unlink( $tmp); # no check, it could not be there 79 | my $t1= XML::Twig->nparse( $doc)->safe_print_to_file( $tmp); 80 | ok( -f $tmp, "safe_print_to_file created document"); 81 | my $t2= XML::Twig->nparse( $tmp); 82 | is( $t2->sprint, $t1->sprint, "generated document identical to original document"); 83 | unlink( $tmp); 84 | 85 | my $e1= XML::Twig->parse( 'foobar')->first_elt( 'b')->safe_print_to_file( $tmp); 86 | ok( -f $tmp, "safe_print_to_file on elt created document"); 87 | $t2= XML::Twig->nparse( $tmp); 88 | is( $t2->sprint, 'bar', "generated sub-document identical to original sub-document"); 89 | unlink( $tmp); 90 | 91 | # failure modes 92 | eval { XML::Twig->nparse( $tmp); }; 93 | like( $@, qr/Couldn't open $tmp:/, 'parse a non-existent file'); 94 | my $non_existent="safe_non_existent_I_hope_01/tmp"; 95 | while( -f $non_existent) { $non_existent++; } # most likely unnecessary ;--) 96 | eval { $t1->safe_print_to_file( $non_existent); }; 97 | like( $@, qr/(does not exist|is not a directory)/, 'safe_print_to_file in non-existent dir'); 98 | } 99 | 100 | exit; 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /t/zz_dump_config.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | 4 | my $ok; # global, true if the last call to version found the module, false otherwise 5 | use Config; 6 | 7 | warn "\n\nConfiguration:\n\n"; 8 | 9 | # required 10 | warn "perl: $]\n"; 11 | warn "OS: $Config{'osname'} - $Config{'myarchname'}\n"; 12 | 13 | print "\n"; 14 | 15 | warn "required\n"; 16 | warn version( XML::Parser, ''); 17 | 18 | # We obviously have expat on VMS, but a symbol/logical might 19 | # not be set to xmlwf, and when this is the case a 20 | # '%DCL-W-IVVERB, unrecognized command verb - check validity and spelling 21 | # \XMLWF\' 22 | # will be returned. 23 | 24 | my $skip_xmlwf_test = 0; 25 | if ($^O eq 'VMS') { 26 | if(`write sys\$output "''xmlwf'"` !~ m/[a-z]+/i) { 27 | $skip_xmlwf_test = 1; 28 | warn format_warn( 'expat', "Skipping expat (version) test as don't have a symbol for 'xmlwf'."); 29 | } 30 | } 31 | 32 | if (! $skip_xmlwf_test) 33 | { # try getting this info 34 | my $xmlwf_v= `xmlwf -v`; 35 | if( $xmlwf_v=~ m{xmlwf using expat_(.*)$}m) 36 | { warn format_warn( 'expat', $1, '(required)'); } 37 | else 38 | { warn format_warn( 'expat', ''); } 39 | } 40 | 41 | warn version( Scalar::Util, 'for improved memory management'); 42 | if( $ok) 43 | { unless( defined( &Scalar::Util::weaken)) 44 | { warn format_warn( '', 'NOT USED, weaken not available in this version'); 45 | warn version( WeakRef); 46 | } 47 | } 48 | else 49 | { warn version( WeakRef, 'for improved memory management'); } 50 | 51 | print "\n"; 52 | 53 | 54 | # must-have 55 | warn "Strongly Recommended\n"; 56 | # encoding 57 | warn version( Encode, 'for encoding conversions'); 58 | unless( $ok) { warn version( Text::Iconv, 'for encoding conversions'); } 59 | unless( $ok) { warn version( Unicode::Map8, 'for encoding conversions'); } 60 | 61 | print "\n"; 62 | 63 | # optional 64 | warn "Modules providing additional features\n"; 65 | warn version( XML::XPathEngine, 'to use XML::Twig::XPath'); 66 | warn version( XML::XPath, 'to use XML::Twig::XPath if XML::XPathEngine not available'); 67 | warn version( LWP, 'for the parseurl method'); 68 | warn version( HTML::TreeBuilder, 'to use parse_html and parsefile_html'); 69 | warn version( HTML::Entities::Numbered, 'to allow parsing of HTML containing named entities'); 70 | warn version( HTML::Tidy, 'to use parse_html and parsefile_html with the use_tidy option'); 71 | warn version( HTML::Entities, 'for the html_encode filter'); 72 | warn version( Tie::IxHash, 'for the keep_atts_order option'); 73 | warn version( Text::Wrap, 'to use the "wrapped" option for pretty_print'); 74 | 75 | print "\n"; 76 | 77 | # used in tests 78 | warn "Modules used only by the auto tests\n"; 79 | warn version( Test, ''); 80 | warn version( Test::Pod, ''); 81 | warn version( XML::Simple, ''); 82 | warn version( XML::Handler::YAWriter, ''); 83 | warn version( XML::SAX::Writer, ''); 84 | warn version( XML::Filter::BufferText, ''); 85 | warn version( IO::Scalar, ''); 86 | warn version( IO::CaptureOutput, ''); 87 | 88 | my $zz_dump_config= File::Spec->catfile( t => "zz_dump_config.t"); 89 | warn "\n\nPlease add this information to bug reports (you can run $zz_dump_config to get it)\n\n"; 90 | warn "if you are upgrading the module from a previous version, make sure you read the\n", 91 | "Changes file for bug fixes, new features and the occasional COMPATIBILITY WARNING\n\n"; 92 | 93 | print "1..1\nok 1\n"; 94 | exit 0; 95 | 96 | sub version 97 | { my $module= shift; 98 | my $info= shift || ''; 99 | $info &&= "($info)"; 100 | my $version; 101 | if( eval "require $module") 102 | { $ok=1; 103 | import $module; 104 | $version= ${"$module\::VERSION"}; 105 | $version=~ s{\s*$}{}; 106 | } 107 | else 108 | { $ok=0; 109 | $version= ''; 110 | } 111 | return format_warn( $module, $version, $info); 112 | } 113 | 114 | sub format_warn 115 | { return sprintf( " %-25s: %16s %s\n", @_); } 116 | -------------------------------------------------------------------------------- /t/test_3_50.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use XML::Twig; 7 | use Test::More tests => 18; 8 | 9 | use utf8; 10 | 11 | SKIP: { 12 | if( XML::Twig::_use( 'XML::XPathEngine') && XML::Twig::_use( 'XML::Twig::XPath')) 13 | { ok( XML::Twig::XPath->new()->parse('')->findnodes('//namespace::*'), '//namespace::* does not crash'); } 14 | else 15 | { skip 'cannot use XML::Twig::XPath', 1; } 16 | } 17 | 18 | { 19 | my $doc=q{titlep 1p 2}; 20 | my $out; 21 | open( my $out_fh, '>', \$out); 22 | my $t= XML::Twig->new ( twig_handlers => { _default_ => sub { $_->flush( $out_fh); } }); 23 | $t->parse( $doc); 24 | is( $out, $doc, 'flush with _default_ handler'); 25 | } 26 | 27 | { 28 | my $doc=q{titlep 1p 2}; 29 | my $out; 30 | open( my $out_fh, '>', \$out); 31 | my $t= XML::Twig->new ( twig_handlers => { 'd' => sub { $_->flush( $out_fh); } }); 32 | $t->parse( $doc); 33 | #is( $out, $doc, 'flush with handler on the root'); 34 | } 35 | 36 | 37 | { # test notations 38 | my $doc=q{ 39 | 41 | 42 | 43 | 44 | 45 | ]> 46 | 47 | DirectionalLight { direction 0 -1 0 } 48 | XML::Twig->parse( 'file.xml'); 49 | 50 | }; 51 | my $t= XML::Twig->parse( $doc); 52 | my $n= $t->notation_list; 53 | is( join( ':', sort $t->notation_names), 'perl:vrml', 'notation_names'); 54 | is( join( ':', sort map { $_->name } $n->list), 'perl:vrml', 'notation_list (names)'); 55 | is( join( ':', sort map { $_->pubid } $n->list), 'Perl 22.4:VRML 1.0', 'notation_list (pubid)'); 56 | is( join( ':', sort map { $_->sysid || '' } $n->list), ':/usr/bin/perl', 'notation_list (pubid)'); 57 | is( $n->notation( 'perl')->pubid, 'Perl 22.4', 'individual notation pubid'); 58 | is( $n->notation( 'vrml')->base, undef, 'individual notation base'); 59 | is( $n->text, qq{\n}, 'all notations'); 60 | my $notations= () = ( $t->sprint() =~ m{sprint( update_DTD => 1) =~ m{delete( 'perl'); 65 | $notations= () = ( $t->sprint( update_DTD => 1) =~ m{notation( 'vrml')->pubid(), 'VRML 1.0', 'notation method'); 68 | $n->add_new_notation( 'svg', '', 'image/svg', 'SVG'); 69 | is( $n->notation( 'svg')->text, qq{}, 'new notation'); 70 | 71 | } 72 | 73 | { # somehow these were never tested (they are inlined within the module) 74 | my $t= XML::Twig->parse( ''); 75 | my $d= $t->root; 76 | 77 | my $e2= $t->first_elt( 'e2'); 78 | my $e1= XML::Twig::Elt->new( 'e1'); 79 | $d->set_first_child( $e1); 80 | $e2->set_prev_sibling( $e1); 81 | $e1->set_next_sibling( $e2); 82 | is( $t->sprint, '', 'set_first_child'); 83 | 84 | my $e3= XML::Twig::Elt->new( 'e3'); 85 | $d->set_last_child( $e3); 86 | $e2->set_next_sibling( $e3); 87 | $e3->set_prev_sibling( $e2); 88 | is( $t->sprint, '', 'set_last_child'); 89 | 90 | $e2->insert_new_elt( first_child => '#PCDATA')->_set_pcdata( 'foo'); 91 | is( $t->sprint, 'foo', '_set_pcdata'); 92 | 93 | $e1->insert_new_elt( first_child => '#CDATA')->_set_cdata( 'bar'); 94 | is( $t->sprint, 'foo', '_set_cdata'); 95 | } 96 | 97 | exit; 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /t/test_3_38.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use Carp; 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | 10 | $|=1; 11 | my $DEBUG=0; 12 | 13 | use XML::Twig; 14 | 15 | my $TMAX=21; 16 | print "1..$TMAX\n"; 17 | 18 | my $d= ''; 19 | 20 | { my $r= XML::Twig->parse( $d)->root; 21 | my $result = $r->att('a'); 22 | is( $r->sprint, $d, 'att'); 23 | } 24 | 25 | 26 | { my $r= XML::Twig->parse( $d)->root; 27 | my $result = foo($r->att('a')); 28 | is( $r->sprint, $d, 'att in sub(1)'); 29 | } 30 | 31 | { my $r= XML::Twig->parse( $d)->root; 32 | my $result = sub { return @_ }->($r->att('a')); 33 | is( $r->sprint, $d, 'att in anonymous sub'); 34 | } 35 | 36 | { my $r= XML::Twig->parse( $d)->root; 37 | my $a= $r->att( 'a'); 38 | is( $r->sprint, $d, 'att in scalar context'); 39 | } 40 | 41 | { my $r= XML::Twig->parse( $d)->root; 42 | my( $a1, $a2)= ($r->att( 'a1'), $r->att( 'a2')); 43 | is( $r->sprint, $d, 'att in list context'); 44 | } 45 | 46 | { my $r= XML::Twig->parse( $d)->root; 47 | $r->att( 'a'); 48 | is( $r->sprint, $d, 'att in void context'); 49 | } 50 | 51 | { my $r= XML::Twig->parse( $d)->root; 52 | my $result = $r->att('a'); 53 | is( $r->sprint, $d, 'att'); 54 | } 55 | 56 | 57 | { my $r= XML::Twig->parse( $d)->root; 58 | my $result = foo($r->class); 59 | is( $r->sprint, $d, 'class in sub(1)'); 60 | } 61 | 62 | { my $r= XML::Twig->parse( $d)->root; 63 | my $result = sub { return @_ }->($r->class); 64 | is( $r->sprint, $d, 'att in anonymous sub'); 65 | } 66 | 67 | { my $r= XML::Twig->parse( $d)->root; 68 | my $a= $r->class; 69 | is( $r->sprint, $d, 'class in scalar context'); 70 | } 71 | 72 | { my $r= XML::Twig->parse( $d)->root; 73 | my( $a1, $a2)= ($r->class, $r->class); 74 | is( $r->sprint, $d, 'class in list context'); 75 | } 76 | 77 | { my $r= XML::Twig->parse( $d)->root; 78 | $r->class; 79 | is( $r->sprint, $d, 'class in void context'); 80 | } 81 | 82 | { my $t= XML::Twig->new->parse( ''); 83 | $t->root->latt( 'a')= 1; 84 | is( $t->sprint, '', 'latt'); 85 | } 86 | 87 | { my $r= XML::Twig->parse( $d)->root; 88 | my $att= $r->att( 'foo'); 89 | is( $att, undef, 'unexisting att'); 90 | } 91 | 92 | 93 | # my $value = $root->att('any_attribute'); 94 | # $result = length($value); 95 | 96 | sub foo { return @_; } 97 | 98 | { 99 | my $r; 100 | my $doc='<_e id="e1"><_e id="e2"><_foo a="2" id="foo"/>'; 101 | my $t= XML::Twig->new( twig_handlers => { _e => sub { $r.= $_->id } }) 102 | ->parse( $doc); 103 | is( $r, 'e1e2', 'handler, condition on tag starting with an underscore'); 104 | is( $t->first_elt( '_foo')->id, 'foo', 'navigation, element name starts with underscore'); 105 | is( $t->first_elt( '*[@_a="2"]')->id, 'bar', 'navigation, attribute name starts with underscore'); 106 | } 107 | 108 | { if( _use( 'LWP') && _use( 'HTML::TreeBuilder') ) 109 | { my $html=q{

Title

foo
bar

}; 110 | my $expected= qq{

Title

foo
bar

}; 111 | 112 | my $html_file= "t/test_3_38.html"; 113 | spit( $html_file, $html); 114 | is( scrub_xhtml( XML::Twig->new( )->parseurl_html( "file:$html_file")->sprint), $expected, 'parseurl_html'); 115 | unlink $html_file; 116 | } 117 | else 118 | { skip( 1, "LWP and/or HTML::TreeBuilder not available, cannot test safe_parseurl_html"); } 119 | 120 | 121 | } 122 | 123 | { my $doc=" foo bar baz"; 124 | is( XML::Twig->parse( $doc)->simplify( normalize_space => 2)->{e}, 'foo bar baz', 'simplify with normalize_space => 2'); 125 | } 126 | 127 | 128 | { my $doc="foo bar foofoo foobar totofoo"; 129 | my $t= XML::Twig->parse( $doc); 130 | is( $t->subs_text( qr/(f)o(o)/, '&elt(b => $1) $2')->sprint, 'f o bar f of o f obar totof o', 'complex subs_text'); 131 | } 132 | 133 | 134 | { my $t= XML::Twig->parse( 'e1e2'); 135 | is( join( '-', $t->findvalues( '//e')), 'e1-e2', 'findvalues'); 136 | } 137 | 138 | 139 | 1; 140 | -------------------------------------------------------------------------------- /speedup.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use 5.010; 4 | 5 | my $FIELD = join( '|', qw( parent first_child last_child prev_sibling next_sibling pcdata cdata ent data target cdata pcdata comment flushed)); 6 | my $PRIVATE = join( '|', qw( parent first_child last_child prev_sibling next_sibling pcdata cdata comment 7 | extra_data_in_pcdata extra_data_before_end_tag 8 | ) 9 | ); # _$private is inlined 10 | my $FORMER = join( '|', qw( parent prev_sibling next_sibling)); # former_$former is inlined 11 | my $SET_FIELD = join( '|', qw( first_child next_sibling ent data pctarget comment flushed)); 12 | my $SET_NOT_EMPTY= join( '|', qw( pcdata cdata comment)); # set the field 13 | 14 | my $var= '(\$[a-z_]+(?:\[\d\])?|\$t(?:wig)?->root|\$t(?:wig)?->twig_current|\$t(?:wig)?->\{\'?twig_root\'?\}|\$t(?:wig)?->\{\'?twig_current\'?\})'; 15 | 16 | my $set_to = '(?:undef|\$\w+|\$\w+->\{\w+\}|\$\w+->\w+|\$\w+->\w+\([^)]+\))'; 17 | my $elt = '\$(?:elt|new_elt|child|cdata|ent|_?parent|twig_current|next_sibling|first_child|prev_sibling|last_child|ref|elt->_parent)'; 18 | 19 | 20 | my %gi2index=( '', 0, PCDATA => 1, CDATA => 2, PI => 3, COMMENT => 4, ENT => 5); 21 | 22 | (my $version= $])=~ s{\.}{}g; 23 | 24 | my $in_pod = 0; # do not change the POD! 25 | 26 | while( <>) 27 | { 28 | $in_pod = 1 if m{^__END__}; 29 | # do not fix the pod 30 | if ($in_pod) { 31 | print $_; 32 | next; 33 | } 34 | 35 | if( /=/) 36 | { s/$var->_children/do { my \$elt= $1; my \@children=(); my \$child= \$elt->_first_child; while( \$child) { push \@children, \$child; \$child= \$child->_next_sibling; } \@children; }/; } 37 | 38 | s/$var->set_gi\(\s*(PCDATA|CDATA|PI|COMMENT|ENT)\s*\)/$1\->{gi}= $gi2index{$2}/; 39 | 40 | s/$var->del_(twig_current)/delete $1\->{'$2'}/g; 41 | s/$var->set_(twig_current)/$1\->{'$2'}=1/g; 42 | s/$var->_del_(flushed)/delete $1\->{'$2'}/g; 43 | s/$var->_set_(flushed)/$1\->{'$2'}=1/g; 44 | s/$var->_(flushed)/$1\->{'$2'}/g; 45 | 46 | s/$var->set_($SET_FIELD)\(([^)]*)\)/$1\->\{$2\}= $3/g; 47 | s/$var->($FIELD)\b(?!\()/$1\->\{$2\}/g; 48 | s/$var->_($PRIVATE)\b(\s*\(\s*\))?(?!\s*\()/$1\->\{$2\}/g; 49 | 50 | s{($elt)->former_($FORMER)}{($1\->{former} && $1\->{former}\->{$2})}g; 51 | 52 | s{($elt)->set_(parent|prev_sibling)\(\s*($set_to)\s*\)}{$1\->\{$2\}=$3; weaken( $1\->\{$2\}); }g; 53 | s{($elt)->set_(first_child)\(\s*($set_to)\s*\)}{ $1\->set_not_empty; $1\->\{$2\}=$3; }g; 54 | s{($elt)->set_(next_sibling)\(\s*($set_to)\s*\)}{ $1\->\{$2\}=$3; }g; 55 | s{($elt)->set_(last_child)\(\s*($set_to)\s*\)}{ $1\->set_not_empty; $1\->\{$2\}=$3; weaken( $1\->\{$2\}); }g; 56 | 57 | s/$var->atts/$1\->{att}/g; 58 | 59 | s/$var->append_(pcdata|cdata)\(([^)]*)\)/$1\->\{$2\}.= $3/g; 60 | s/$var->set_($SET_NOT_EMPTY)\(([^)]*)\)/$1\->\{$2\}= (delete $1->\{empty\} || 1) && $3/g; 61 | s/$var->_set_($SET_NOT_EMPTY)\s*\(([^)]*)\)/$1\->{$2}= $3/g; 62 | 63 | s/(\$[a-z][a-z_]*(?:\[\d\])?)->gi/\$XML::Twig::index2gi\[$1\->{'gi'}\]/g; 64 | 65 | s/$var->id/$1\->{'att'}->{\$ID}/g; 66 | s/$var->att\(\s*([^)]+)\)/$1\->{'att'}->\{$2\}/g; 67 | 68 | s/(\$[a-z][a-z_]*(?:\[\d\])?)->is_pcdata/(exists $1\->{'pcdata'})/g; 69 | s/(\$[a-z][a-z_]*(?:\[\d\])?)->is_cdata/(exists $1\->{'cdata'})/g; 70 | s/$var->is_pi/(exists $1\->{'target'})/g; 71 | s/$var->is_comment/(exists $1\->{'comment'})/g; 72 | s/$var->is_ent/(exists $1\->{'ent'})/g; 73 | s/(\$,a-z][a-z_]*(?:\[\d\])?)->is_text/((exists $1\->{'pcdata'}) || (exists $1\->{'cdata'}))/g; 74 | 75 | s/$var->is_empty/$1\->{'empty'}/g; 76 | s/$var->set_empty(?:\(([^)]*)\))?(?!_)/"$1\->{empty}= " . ($2 || 1)/ge; 77 | s/$var->set_not_empty/delete $1\->{empty}/g; 78 | 79 | s/$var->_is_private/( (substr( \$XML::Twig::index2gi\[$1\->{'gi'}\], 0, 1) eq '#') && (substr( \$XML::Twig::index2gi\[$1\->{'gi'}\], 0, 9) ne '#default:') )/g; 80 | s/_is_private_name\(\s*$var\s*\)/( $1=~ m{^#(?!default:)} )/g; 81 | 82 | s{_is_fh\(\s*$var\)}{isa( $1, 'GLOB') || isa( $1, 'IO::Scalar')}g; 83 | 84 | s/$var->set_gi\s*\(\s*([^)]*)\s*\)/$1\->{gi}=\$XML::Twig::gi2index{$2} or $1->set_gi( $2)/g; 85 | 86 | s/$var->xml_string/$1->sprint( 1)/g; 87 | 88 | print $_ ; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /t/test3.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | 6 | use File::Spec; 7 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 8 | use tools; 9 | 10 | # This just tests a complete twig, no callbacks 11 | # additional tests for element creation/parse and 12 | # space policy 13 | # plus test for the is_pcdata method 14 | 15 | $|=1; 16 | 17 | use XML::Twig; 18 | 19 | my $i=0; 20 | my $failed=0; 21 | 22 | my $TMAX=23; # do not forget to update! 23 | 24 | print "1..$TMAX\n"; 25 | 26 | my $p1= XML::Twig::Elt->new( 'para', 'p1'); 27 | $p1->set_id( 'p1'); 28 | etest( $p1, 'para', 'p1', 'Element creation'); 29 | my $p2= XML::Twig::Elt->parse( 'para2'); 30 | etest( $p2, 'para', 'p2', 'Element parse'); 31 | my $s1= parse XML::Twig::Elt( '
title1para 3
'); 32 | etest( $s1, 'section', 's1', 'Element parse (complex)'); 33 | my $p3= $s1->first_child( 'para'); 34 | etest( $p3, 'para', 'p3', 'Element parse (sub-element)'); 35 | 36 | my $string= "\n

para

\n

\n
"; 37 | 38 | my $t1= new XML::Twig( DiscardSpacesIn => [ 'doc']); 39 | $t1->parse( $string); 40 | sttest( $t1->root, "

para

\n

", 'DiscardSpacesIn'); 41 | my $t2= new XML::Twig( DiscardSpacesIn => [ 'doc', 'p']); 42 | $t2->parse( $string); 43 | sttest( $t2->root, "

para

", 'DiscardSpacesIn'); 44 | my $t3= new XML::Twig( KeepSpaces =>1); 45 | $t3->parse( $string); 46 | sttest( $t3->root, $string, 'KeepSpaces'); 47 | my $t4= new XML::Twig( KeepSpacesIn =>[ 'p']); 48 | $t4->parse( $string); 49 | sttest( $t4->root, "

para

\n

", 'KeepSpacesIn'); 50 | 51 | 52 | my $p4= XML::Twig::Elt->parse( $string, KeepSpaces => 1); 53 | sttest( $p4, $string, 'KeepSpaces'); 54 | 55 | my $p5= XML::Twig::Elt->parse( $string, DiscardSpaces => 1); 56 | sttest( $p5, '

para

', "DiscardSpaces"); 57 | 58 | $p5= XML::Twig::Elt->parse( $string); 59 | sttest( $p5, '

para

', "DiscardSpaces (def)"); 60 | 61 | my $p6= XML::Twig::Elt->parse( $string, KeepSpacesIn => ['p']); 62 | sttest( $p6, "

para

\n

", "KeepSpacesIn 1"); 63 | 64 | my $p7= XML::Twig::Elt->parse( $string, KeepSpacesIn => [ 'doc', 'p']); 65 | sttest( $p7, "\n

para

\n

\n
", "KeepSpacesIn 2"); 66 | 67 | my $p8= XML::Twig::Elt->parse( $string, DiscardSpacesIn => ['doc']); 68 | sttest( $p8, "

para

\n

", "DiscardSpacesIn 1 "); 69 | 70 | my $p9= XML::Twig::Elt->parse( $string, DiscardSpacesIn => [ 'doc', 'p']); 71 | sttest( $p9, "

para

", "DiscardSpacesIn 2"); 72 | 73 | my $string2= "

para bold end of para

"; 74 | my $p10= XML::Twig::Elt->parse( $string2,); 75 | sttest( $p10, '

para bold end of para

', "mixed content"); 76 | 77 | my $string3= "\n

para

\n

\n

\n
"; 78 | my $p11= XML::Twig::Elt->parse( $string3, KeepSpaces => 1); 79 | sttest( $p4, $string, 'KeepSpaces'); 80 | my $p12= XML::Twig::Elt->parse( $string3, KeepSpacesIn => [ 'doc']); 81 | sttest( $p12, "\n

para

\n

\n
", 'KeepSpacesIn'); 82 | my $p13= XML::Twig::Elt->parse( $string3, KeepSpaces => 1); 83 | sttest( $p13, "\n

para

\n

\n

\n
", 'KeepSpaces'); 84 | 85 | my $p14= XML::Twig::Elt->parse( $string2); 86 | my $is_pcdata= $p14->is_pcdata; 87 | ok( $is_pcdata ? 0 : 1, "is_pcdata on a "); 88 | my $pcdata= $p14->first_child( PCDATA); 89 | $is_pcdata= $pcdata->is_pcdata; 90 | ok( $pcdata->is_pcdata, "is_pcdata on PCDATA"); 91 | 92 | my $erase_string='text 1 text 2 text 3 text 4'; 96 | my $er_t= new XML::Twig( TwigHandlers => { selt => sub { $_[1]->erase; } }); 97 | $er_t->parse( $erase_string); 98 | sttest( $er_t->root, 'text 1 text 2 text 3 text 4', 99 | "erase"); 100 | 101 | # test whether Twig packs strings 102 | my $br_pcdata= "line 1\nline 2\nline 3\n"; 103 | my $doc_br_pcdata= "$br_pcdata"; 104 | my $t_br_pcdata= new XML::Twig(); 105 | $t_br_pcdata->parse( $doc_br_pcdata); 106 | $pcdata= $t_br_pcdata->root->first_child->pcdata; 107 | stest( $pcdata, $br_pcdata, "multi-line pcdata"); 108 | 109 | exit 0; 110 | 111 | -------------------------------------------------------------------------------- /t/xmlxpath_31vars.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | 5 | use FindBin qw($Bin); BEGIN { unshift @INC, $Bin; } use xmlxpath_tools; 6 | 7 | use Test::More; 8 | 9 | use XML::Twig::XPath; 10 | 11 | eval "use XML::XPathEngine"; 12 | if( $@) { print "1..1\nok 1\n"; warn "skipping, using variables in XPath requires XML::XPathEngine\n"; exit; } 13 | 14 | plan( tests => 8); 15 | 16 | my( $employees, $areas)= do { local $/="\n\n"; ; }; 17 | 18 | { 19 | # test all data in 1 single file 20 | my $data= "$employees$areas"; 21 | my $t = XML::Twig::XPath->new->parse( $data); 22 | 23 | { $t->set_var( salary => 12000); 24 | my @nodes= $t->findnodes('/data/employees/employee[@salary=$salary]/name'); 25 | is( results( @nodes), 'e3:e4', '1 doc, var is a litteral'); 26 | } 27 | 28 | { $t->set_var( E => $t->find( '/data/employees/employee[@salary>10000]')); 29 | $t->set_var( A => $t->find( '/data/areas/area[district="Brooklyn"]/street')); 30 | my @nodes = $t->findnodes('$E[work_area/street = $A]/name'); 31 | is( results( @nodes), 'e3:e4', '1 doc, var is a node set'); 32 | } 33 | 34 | { $t->set_var( org => 'A'); 35 | my @nodes= $t->findnodes('/data/employees/employee[@org=$org]/name'); 36 | is( results( @nodes), 'e5', '1 doc, var is a simple litteral'); 37 | } 38 | 39 | { $t->set_var( org => 'A/B'); 40 | my @nodes= $t->findnodes('/data/employees/employee[@org=$org]/name'); 41 | is( results( @nodes), 'e6', '1 doc, var is an XPath-like litteral'); 42 | } 43 | 44 | } 45 | 46 | { # test with data in 2 single file 47 | my $te = XML::Twig::XPath->new->parse( $employees); 48 | my $ta = XML::Twig::XPath->new->parse( $areas); 49 | 50 | { $te->set_var( salary => 12000); 51 | my @nodes= $te->findnodes('/employees/employee[@salary=$salary]/name'); 52 | is( results( @nodes), 'e3:e4', '2 docs, var is a litteral'); 53 | } 54 | 55 | SKIP: 56 | { skip "node sets in an XPath variable are not supported with perl < 5.12", 1 unless $] >= 5.012; 57 | $te->set_var( E => $te->find( '/employees/employee[@salary>10000]')); 58 | $te->set_var( A => $ta->find( '/areas/area[district="Brooklyn"]/street')); 59 | my @nodes = $te->findnodes('$E[work_area/street = $A]/name'); 60 | is( results( @nodes), 'e3:e4', '2 docs, var is a node set'); 61 | } 62 | 63 | { $te->set_var( org => 'A'); 64 | my @nodes= $te->findnodes('/employees/employee[@org=$org]/name'); 65 | is( results( @nodes), 'e5', '2 docs, var is a simple litteral'); 66 | } 67 | 68 | { $te->set_var( org => 'A/B'); 69 | my @nodes= $te->findnodes('/employees/employee[@org=$org]/name'); 70 | is( results( @nodes), 'e6', '2 docs, var is an XPath-like litteral'); 71 | } 72 | 73 | } 74 | 75 | 76 | sub results 77 | { return join ':', map { $_->id || 'XX' } @_; } 78 | 79 | __DATA__ 80 | 81 | 82 | Employee 1 83 | 84 | Fifth Avenue 85 | 86 | 87 | 88 | Employee 2 89 | 90 | Abbey Court 91 | 92 | 93 | 94 | Employee 3 95 | 96 | Abbey Court 97 | 98 | 99 | 100 | Employee 4 101 | 102 | Broad Street 103 | Abbey Court 104 | 105 | 106 | 107 | Employee 5 108 | 109 | Broad Street 110 | Abbey Court 111 | 112 | 113 | 114 | Employee 6 115 | 116 | Broad Street 117 | Abbey Court 118 | 119 | 120 | 121 | 122 | 123 | 124 | Brooklyn 125 | Abbey Court 126 | Aberdeen Street 127 | Adams Street 128 | 129 | 130 | Manhattan 131 | Fifth Avenue 132 | Broad Street 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /tools/xml_merge/xml_merge: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # $Id: /xmltwig/trunk/tools/xml_merge/xml_merge 12 2007-04-22T06:04:54.627880Z mrodrigu $ 3 | use strict; 4 | 5 | use XML::Twig; 6 | use FindBin qw( $RealBin $RealScript); 7 | use Getopt::Std; 8 | 9 | $Getopt::Std::STANDARD_HELP_VERSION=1; # to stop processing after --help or --version 10 | 11 | use vars qw( $VERSION $USAGE); 12 | 13 | $VERSION= "0.02"; 14 | $USAGE= "xml_merge [-o ] [-i] [-v] [-h] [-m] [-V] [file]\n"; 15 | 16 | { # main block 17 | 18 | my $opt={}; 19 | getopts('o:ivhmV', $opt); 20 | 21 | if( $opt->{h}) { die $USAGE, "\n"; } 22 | if( $opt->{m}) { exec "pod2text $RealBin/$RealScript"; } 23 | if( $opt->{V}) { print "xml_merge version $VERSION\n"; exit; } 24 | 25 | if( $opt->{o}) 26 | { open( my $out, '>', $opt->{o}) or die "cannot create $opt->{o}: $!"; 27 | $opt->{fh}= $out; # used to set twig_print_outside_roots 28 | } 29 | else 30 | { $opt->{fh}= 1; } # this way twig_print_outside_roots outputs to STDOUT 31 | 32 | $opt->{subdocs} = 1; 33 | $opt->{file} = $ARGV[0]; 34 | 35 | $opt->{twig_roots}= $opt->{i} ? { 'xi:include' => sub { $opt->{file}= $_->att( 'href'); 36 | if( $_->att( 'subdocs')) { merge( $opt); } 37 | else { spit( $opt); } 38 | }, 39 | } 40 | : { '?merge' => sub { $opt= parse( $_->data, $opt); 41 | if( $opt->{subdocs}) { merge( $opt); } 42 | else { spit( $opt); } 43 | }, 44 | } 45 | 46 | ; 47 | 48 | merge( $opt); 49 | 50 | if( $opt->{v}) { warn "done\n"; } 51 | 52 | } 53 | 54 | sub merge 55 | { my( $opt)= @_; 56 | my $t= XML::Twig->new( keep_encoding => 1, keep_spaces => 1, 57 | twig_roots => $opt->{twig_roots}, 58 | twig_print_outside_roots => $opt->{fh}, 59 | ); 60 | if( $opt->{v} && $opt->{file}) { warn "merging $opt->{file} (parsing)\n"; } 61 | if( $opt->{file}) { $t->parsefile( $opt->{file}); } else { $t->parse( \*STDIN); } 62 | } 63 | 64 | sub spit 65 | { my( $opt)= @_; 66 | if( $opt->{v} && $opt->{file}) { warn "merging $opt->{file} (no parsing)\n"; } 67 | open( my $in, '<', $opt->{file}) or die "cannot open sub document '$opt->{file}': $!"; 68 | while( <$in>) 69 | { next if( m{^\Q{o}) { print {$opt->{fh}} $_; } else { print $_; } 71 | } 72 | close $in; 73 | } 74 | 75 | # data is the pi data, 76 | # (ugly) format is keyword1 = val1 : keyword2 = val2 ... : filename 77 | # ex: subdoc = 1 : file-01.xml 78 | 79 | sub parse 80 | { my( $data, $opt)= @_; 81 | while( $data=~ s{^\s*(\S+)\s*=\s*(\S+)\s*:\s*}{}) { $opt->{$1}= $2; } 82 | $opt->{file}= $data; 83 | return $opt; 84 | } 85 | 86 | 87 | # for Getop::Std 88 | sub HELP_MESSAGE { return $USAGE; } 89 | sub VERSION_MESSAGE { return $VERSION; } 90 | 91 | __END__ 92 | 93 | =head1 NAME 94 | 95 | xml_merge - merge back XML files split with C 96 | 97 | =head1 DESCRIPTION 98 | 99 | C takes several xml files that have been split using 100 | C and recreates a single file. 101 | 102 | =head1 OPTIONS 103 | 104 | =over 4 105 | 106 | =item -o 107 | 108 | unless this option is used the program output goes to STDOUT 109 | 110 | =item -i 111 | 112 | the files use XInclude instead of processing instructions (they 113 | were created using the C<-i> option in C) 114 | 115 | =item -v 116 | 117 | verbose output 118 | 119 | =item -V 120 | 121 | outputs version and exit 122 | 123 | =item -h 124 | 125 | short help 126 | 127 | =item -m 128 | 129 | man (requires pod2text to be in the path) 130 | 131 | =back 132 | 133 | =head1 EXAMPLES 134 | 135 | xml_merge foo-00.xml # output to stdout 136 | xml_merge -o foo.xml foo-00.xml # output to foo.xml 137 | 138 | =head1 SEE ALSO 139 | 140 | XML::Twig, xml_split 141 | 142 | =head1 TODO/BUGS 143 | 144 | =head1 AUTHOR 145 | 146 | Michel Rodriguez 147 | 148 | =head1 LICENSE 149 | 150 | This tool is free software; you can redistribute it and/or modify 151 | it under the same terms as Perl itself. 152 | 153 | -------------------------------------------------------------------------------- /t/test_bugs_3_21.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use strict; 6 | use Carp; 7 | use File::Spec; 8 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 9 | use tools; 10 | 11 | $|=1; 12 | my $DEBUG=0; 13 | 14 | use XML::Twig; 15 | 16 | my $TMAX=25; 17 | print "1..$TMAX\n"; 18 | 19 | { # testing creation of elements in the proper class 20 | 21 | package foo; use base 'XML::Twig::Elt'; package main; 22 | 23 | my $t= XML::Twig->new( elt_class => "foo")->parse( ''); 24 | my $elt= $t->first_elt( 'elt'); 25 | $elt->set_text( 'bar'); 26 | is( $elt->first_child->text, 'bar', "content of element created with set_text"); 27 | is( ref( $elt->first_child), 'foo', "class of element created with set_text"); 28 | $elt->set_content( 'baz'); 29 | is( $elt->first_child->text, 'baz', "content of element created with set_content"); 30 | is( ref( $elt->first_child), 'foo', "class of element created with set_content"); 31 | $elt->insert( 'toto'); 32 | is( $elt->first_child->tag, 'toto', "tag of element created with set_content"); 33 | is( ref( $elt->first_child), 'foo', "class of element created with insert"); 34 | $elt->insert_new_elt( first_child => 'tata'); 35 | is( $elt->first_child->tag, 'tata', "tag of element created with insert_new_elt"); 36 | is( ref( $elt->first_child), 'foo', "class of element created with insert"); 37 | $elt->wrap_in( 'tutu'); 38 | is( $t->root->first_child->tag, 'tutu', "tag of element created with wrap_in"); 39 | is( ref( $t->root->first_child), 'foo', "class of element created with wrap_in"); 40 | $elt->prefix( 'titi'); 41 | is( $elt->first_child->text, 'titi', "content of element created with prefix"); 42 | is( ref( $elt->first_child), 'foo', "class of element created with prefix"); 43 | $elt->suffix( 'foobar'); 44 | is( $elt->last_child->text, 'foobar', "content of element created with suffix"); 45 | is( ref( $elt->last_child), 'foo', "class of element created with suffix"); 46 | $elt->last_child->split_at( 3); 47 | is( $elt->last_child->text, 'bar', "content of element created with split_at"); 48 | is( ref( $elt->last_child), 'foo', "class of element created with split_at"); 49 | is( ref( $elt->copy), 'foo', "class of element created with copy"); 50 | 51 | $t= XML::Twig->new( elt_class => "foo")->parse( 'toto'); 52 | $t->root->subs_text( qr{(to)} => '&elt( p => $1)'); 53 | is( $t->sprint, '

to

to

', "subs_text result"); 54 | my $result= join( '-', map { join( ":", ref($_), $_->tag) } $t->root->descendants); 55 | is( $result, "foo:p-foo:#PCDATA-foo:p-foo:#PCDATA", "subs_text classes and tags"); 56 | 57 | } 58 | 59 | 60 | { # wrap children with > in attribute 61 | my $doc=q{}; 62 | my $result =XML::Twig->new->parse( $doc)->root->wrap_children( '+', "w")->strip_att( 'id')->sprint; 63 | my $expected = q{}; 64 | is( $result => $expected, "wrap_children with > in attributes"); 65 | $result =XML::Twig->new->parse( $doc)->root->wrap_children( '+', "w")->strip_att( 'id')->sprint; 66 | $expected = q{}; 67 | is( $result => $expected, "wrap_children with > in attributes, > in condition"); 68 | $result =XML::Twig->new->parse( $doc)->root->wrap_children( '+', "w")->strip_att( 'id')->sprint; 69 | $expected = q{}; 70 | is( $result => $expected, "wrap_children with > in attributes un-escaped > in condition"); 71 | $result =XML::Twig->new->parse( $doc)->root->wrap_children( '+', "w")->strip_att( 'id')->sprint; 72 | $expected = q{}; 73 | is( $result => $expected, "wrap_children with > in attributes, 2 atts in condition"); 74 | $result =XML::Twig->new->parse( $doc)->root->wrap_children( '+', "w")->strip_att( 'id')->sprint; 75 | $expected = q{}; 76 | is( $result => $expected, "wrap_children with > in attributes, 2 atts in condition (no child matches)"); 77 | } 78 | 79 | { # test improvements to wrap_children 80 | my $doc= q{okNOK}; 81 | my $expected= q{okNOK}; 82 | my $t= XML::Twig->new->parse( $doc); 83 | $t->root->wrap_children( '+', w => { a => "&" }); 84 | $t->root->strip_att( 'id'); 85 | is( $t->sprint, $expected, "wrap_children with &"); 86 | } 87 | 88 | -------------------------------------------------------------------------------- /t/test_bugs_3_19.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | 5 | use strict; 6 | use Carp; 7 | use File::Spec; 8 | use lib File::Spec->catdir(File::Spec->curdir,"t"); 9 | use tools; 10 | 11 | $|=1; 12 | my $DEBUG=0; 13 | 14 | use XML::Twig; 15 | 16 | my $TMAX=26; 17 | print "1..$TMAX\n"; 18 | 19 | { 20 | #bug with long CDATA 21 | 22 | # get an accented char in iso-8859-1 23 | my $latin1_char= perl_io_layer_used() ? '' : slurp( File::Spec->catfile('t', "latin1_accented_char.iso-8859-1")); 24 | chomp $latin1_char; 25 | 26 | 27 | my %cdata=( "01- 1025 chars" => 'x' x 1025 . 'a', 28 | "02- short CDATA with nl" => "first line\nsecond line", 29 | "03- short CDATA with ]" => "first part]second part", 30 | "04- short CDATA with ] and spaces" => "first part ] second part", 31 | "05- 1024 chars with accent" => $latin1_char x 1023 . 'a', 32 | "06- 1025 chars with accent" => $latin1_char x 1024 . 'a', 33 | "07- 1023 chars, last a nl" => 'x' x 1022 . "\n", 34 | "08- 1023 chars, last a ]" => 'x' x 1022 . "]", 35 | "09- 1024 chars, last a nl" => 'x' x 1023 . "\n", 36 | "10- 1024 chars, last a ]" => 'x' x 1023 . "]", 37 | "11- 1025 chars, last a nl" => 'x' x 1024 . "\n", 38 | "12- 1025 chars, last a ]" => 'x' x 1024 . "]", 39 | "13- 1050 chars, last a nl" => ('1' x 1024) . ('2' x 25) . "\n", 40 | "14- 1050 chars, last a ]" => ('1' x 1024) . ('2' x 25) . "]", 41 | '15- 1060 chars, ] and \n' => ('1' x 1024) . ('2' x 26) . "\n \n ]\n]]\n", 42 | '16- 1060 chars, ] and \n' => ('1' x 1024) . ('2' x 26) . "\n \n ]\n]]", 43 | '17- 1060 chars, ] and \n' => ('1' x 1024) . ('2' x 26) . "\n \n ]\n]] ", 44 | '18- 1060 chars, ] and \n' => ('1' x 1024) . ('2' x 26) . "\n \n ]\n]] a", 45 | '19- 1060 chars, ] and \n' => '1' x 500 . "\n \n ]\n]] a" . '2' x 500 . "\n \n ]\n]] a", 46 | "20- 800 chars with accent" => $latin1_char x 800, 47 | "21- 800 chars with accent" => "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$latin1_char" x 16, 48 | "22- 1600 chars with accent" => "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$latin1_char" x 32, 49 | '23- 1600 chars with accent and \n' => "aaaaaaaa]aaaaaaaaaaaaaaaaaaaaaaaaa\naaaaaaaaaaaaaaa$latin1_char" x 32, 50 | ); 51 | 52 | if( ($] == 5.008) || ($] < 5.006) ) 53 | { skip( scalar keys %cdata, "KNOWN BUG in 5.8.0 and 5.005 with keep_encoding and long (>1024 char) CDATA, " 54 | . "see http://rt.cpan.org/Ticket/Display.html?id=14008" 55 | ); 56 | } 57 | elsif( perl_io_layer_used()) 58 | { skip( scalar keys %cdata, "cannot test parseurl when UTF8 perIO layer used " 59 | . "(due to PERL_UNICODE or -C option used)\n" 60 | ); 61 | } 62 | else 63 | { 64 | foreach my $test (sort keys %cdata) 65 | { my $cdata=$cdata{$test}; 66 | my $doc= qq{}; 67 | my $twig= XML::Twig->new( keep_encoding => 1)->parse($doc); 68 | my $res = $twig->root->first_child->cdata; 69 | is( $res, $cdata, "long CDATA with keep_encoding $test"); 70 | } 71 | } 72 | } 73 | 74 | { # testing _dump 75 | my $doc= q{foobartototatatitiand now a long (more than 40 characters) text to see if it gets shortened by default (or not)}; 76 | my $t= XML::Twig->new->parse( $doc); 77 | my $dump= q{document 78 | |-doc 79 | | |-elt att="xyz" 80 | | |-- (cpi before) '' 81 | | | |-PCDATA: 'foo' 82 | | |-elt 83 | | | |-PCDATA: 'bar' 84 | | | |-CDATA: 'baz' 85 | | |-elt2 86 | | |-- (cpi before) '' 87 | | | |-PCDATA: 'toto' 88 | | | |-b 89 | | | | |-PCDATA: 'tata' 90 | | | |-PCDATA: 'titi' 91 | | |-elt3 92 | | |-elt 93 | | | |-PCDATA: 'and now a long (more than 40 characters) tex ... see if it gets shortened by default (or not)' 94 | }; 95 | 96 | is( $t->_dump( { extra => 1 }), $dump, "_dump with extra on"); 97 | 98 | (my $no_extra= $dump)=~ s{^.*cpi before.*\n}{}gm; 99 | is( $t->_dump( ), $no_extra, "_dump without extra"); 100 | 101 | (my $no_att= $no_extra)=~ s{ att=.*}{}g; 102 | is( $t->_dump( { atts => 0 }), $no_att, "_dump without atts"); 103 | 104 | } 105 | 106 | -------------------------------------------------------------------------------- /t/test_memory.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | use strict; 5 | use Carp; 6 | use File::Spec; 7 | use lib File::Spec->catdir( File::Spec->curdir, "t" ); 8 | use tools; 9 | 10 | $| = 1; 11 | my $DEBUG = 0; 12 | 13 | use XML::Twig; 14 | 15 | # only display warnings, test is too unreliable (especially under Devel::Cover) to trust 16 | 17 | my $mem_size = mem_size(); 18 | 19 | unless ($mem_size) { 20 | print "1..1\nok 1\n"; 21 | warn "skipping: memory size not available\n"; 22 | exit; 23 | } 24 | 25 | my $long_test = $ARGV[0] && $ARGV[0] eq '-L'; 26 | 27 | my $conf 28 | = $long_test 29 | ? { iter => 10, p => 1000 } 30 | : { iter => 5, p => 500 }; 31 | $conf->{normal} = $conf->{p} * $conf->{iter}; 32 | $conf->{normal_html} = $conf->{normal} * 2; 33 | 34 | my $TMAX = 3; 35 | print "1..$TMAX\n"; 36 | 37 | my $warn = 0; 38 | my $test_nb = 0; 39 | 40 | my $paras = join '', map {qq{

lorem ipsus whatever (clever latin stuff) no $_

}} 1 .. $conf->{p}; 41 | 42 | my $xml = qq{$paras}; 43 | XML::Twig->new->parse($xml); 44 | my $before = mem_size(); 45 | for ( 1 .. $conf->{iter} ) { 46 | my $t = XML::Twig->new->parse($xml); 47 | really_clear($t); 48 | } 49 | my $after = mem_size(); 50 | if ( $after - $before > $conf->{normal} ) { 51 | warn "test $test_nb: possible memory leak parsing xml ($after > $before)"; 52 | $warn++; 53 | } elsif ($long_test) { 54 | warn "$before => $after\n"; 55 | } 56 | ok( 1, "testing memory leaks for xml parsing" ); 57 | $test_nb++; 58 | 59 | { 60 | if ( XML::Twig::_use( 'HTML::TreeBuilder', 3.13 ) ) { 61 | my $html = qq{with HTB$paras}; 62 | XML::Twig->new->parse_html($html); 63 | my $before = mem_size(); 64 | for ( 1 .. $conf->{iter} ) { XML::Twig->new->parse_html($html); } 65 | my $after = mem_size(); 66 | if ( $after - $before > $conf->{normal_html} ) { 67 | warn "test $test_nb: possible memory leak parsing html ($after > $before)"; 68 | $warn++; 69 | } elsif ($long_test) { 70 | warn "$before => $after\n"; 71 | } 72 | ok( 1, "testing memory leaks for html parsing" ); 73 | } else { 74 | skip( 1, "need HTML::TreeBuilder 3.13+" ); 75 | } 76 | $test_nb++; 77 | } 78 | 79 | { 80 | if ( XML::Twig::_use('HTML::Tidy') ) { 81 | my $html = qq{with tidy$paras}; 82 | XML::Twig->new( use_tidy => 1 )->parse_html($html); 83 | my $before = mem_size(); 84 | for ( 1 .. $conf->{iter} ) { XML::Twig->new( use_tidy => 1 )->parse_html($html); } 85 | my $after = mem_size(); 86 | if ( $after - $before > $conf->{normal_html} ) { 87 | warn "test $test_nb: possible memory leak parsing html ($after > $before)"; 88 | $warn++; 89 | } elsif ($long_test) { 90 | warn "$before => $after\n"; 91 | } 92 | ok( 1, "testing memory leaks for html parsing using HTML::Tidy" ); 93 | } else { 94 | skip( 1, "need HTML::Tidy" ); 95 | } 96 | $test_nb++; 97 | } 98 | 99 | if ($warn) { 100 | warn "\nnote that memory leaks can happen even if the module itself doesn't leak, if running", 101 | "\ntests under Devel::Cover for example. So do not panic if you get a warning here.\n"; 102 | } 103 | 104 | sub mem_size { 105 | open( STATUS, "/proc/$$/status" ) or return; 106 | my ($size) = map {m{^VmSize:\s+(\d+\s+\w+)}} ; 107 | $size =~ s{ kB}{}; 108 | 109 | #warn "data size found: $size\n"; 110 | return $size; 111 | } 112 | 113 | sub really_clear { 114 | my ($t) = shift; 115 | my $elt = $t->root; 116 | delete $t->{twig_dtd}; 117 | delete $t->{twig_doctype}; 118 | delete $t->{twig_xmldecl}; 119 | delete $t->{twig_root}; 120 | delete $t->{twig_parser}; 121 | 122 | return; 123 | 124 | local $SIG{__WARN__} = sub { }; 125 | 126 | while ($elt) { 127 | my $nelt = nelt($elt); 128 | $elt->del_id($t); 129 | foreach (qw(gi att empty former)) { undef $elt->{$_}; delete $elt->{$_}; } 130 | $elt->delete; 131 | $elt = $nelt; 132 | } 133 | $t->dispose; 134 | } 135 | 136 | sub nelt { 137 | my ($elt) = @_; 138 | if ( $elt->_first_child ) { return deepest_child($elt); } 139 | if ( $elt->_next_sibling ) { return deepest_child( $elt->_next_sibling ); } 140 | return $elt->parent; 141 | } 142 | 143 | sub deepest_child { 144 | my ($elt) = @_; 145 | while ( $elt->_first_child ) { $elt = $elt->_first_child; } 146 | return $elt; 147 | } 148 | --------------------------------------------------------------------------------