| 196 |
$self->{document}->manakai_is_html (0); |
$self->{document}->manakai_is_html (0); |
| 197 |
$self->{document}->set_user_data (manakai_source_line => 1); |
$self->{document}->set_user_data (manakai_source_line => 1); |
| 198 |
$self->{document}->set_user_data (manakai_source_column => 1); |
$self->{document}->set_user_data (manakai_source_column => 1); |
| 199 |
|
|
| 200 |
|
$self->{ge}->{'amp;'} = {value => '&', only_text => 1}; |
| 201 |
|
$self->{ge}->{'apos;'} = {value => "'", only_text => 1}; |
| 202 |
|
$self->{ge}->{'gt;'} = {value => '>', only_text => 1}; |
| 203 |
|
$self->{ge}->{'lt;'} = {value => '<', only_text => 1}; |
| 204 |
|
$self->{ge}->{'quot;'} = {value => '"', only_text => 1}; |
| 205 |
} # _initialize_tree_constructor |
} # _initialize_tree_constructor |
| 206 |
|
|
| 207 |
sub _terminate_tree_constructor ($) { |
sub _terminate_tree_constructor ($) { |
| 220 |
|
|
| 221 |
## XML5: No namespace support. |
## XML5: No namespace support. |
| 222 |
|
|
|
## XML5: XML5 has "empty tag token". In this implementation, it is |
|
|
## represented as a start tag token with $self->{self_closing} flag |
|
|
## set to true. |
|
|
|
|
|
## XML5: XML5 has "short end tag token". In this implementation, it |
|
|
## is represented as an end tag token with $token->{tag_name} flag set |
|
|
## to an empty string. |
|
|
|
|
| 223 |
## XML5: Start, main, end phases. In this implementation, they are |
## XML5: Start, main, end phases. In this implementation, they are |
| 224 |
## represented by insertion modes. |
## represented by insertion modes. |
| 225 |
|
|
| 228 |
sub BEFORE_ROOT_ELEMENT_IM () { 1 } |
sub BEFORE_ROOT_ELEMENT_IM () { 1 } |
| 229 |
sub IN_ELEMENT_IM () { 2 } |
sub IN_ELEMENT_IM () { 2 } |
| 230 |
sub AFTER_ROOT_ELEMENT_IM () { 3 } |
sub AFTER_ROOT_ELEMENT_IM () { 3 } |
| 231 |
|
sub IN_SUBSET_IM () { 4 } |
| 232 |
|
|
| 233 |
{ |
{ |
| 234 |
my $token; ## TODO: change to $self->{t} |
my $token; ## TODO: change to $self->{t} |
| 268 |
while (1) { |
while (1) { |
| 269 |
if ($self->{insertion_mode} == IN_ELEMENT_IM) { |
if ($self->{insertion_mode} == IN_ELEMENT_IM) { |
| 270 |
$self->_tree_in_element; |
$self->_tree_in_element; |
| 271 |
|
} elsif ($self->{insertion_mode} == IN_SUBSET_IM) { |
| 272 |
|
$self->_tree_in_subset; |
| 273 |
} elsif ($self->{insertion_mode} == AFTER_ROOT_ELEMENT_IM) { |
} elsif ($self->{insertion_mode} == AFTER_ROOT_ELEMENT_IM) { |
| 274 |
$self->_tree_after_root_element; |
$self->_tree_after_root_element; |
| 275 |
} elsif ($self->{insertion_mode} == BEFORE_ROOT_ELEMENT_IM) { |
} elsif ($self->{insertion_mode} == BEFORE_ROOT_ELEMENT_IM) { |
| 296 |
|
|
| 297 |
## NOTE: Default value for both |public_id| and |system_id| attributes |
## NOTE: Default value for both |public_id| and |system_id| attributes |
| 298 |
## are empty strings, so that we don't set any value in missing cases. |
## are empty strings, so that we don't set any value in missing cases. |
| 299 |
$doctype->public_id ($token->{public_identifier}) |
$doctype->public_id ($token->{pubid}) if defined $token->{pubid}; |
| 300 |
if defined $token->{public_identifier}; |
$doctype->system_id ($token->{sysid}) if defined $token->{sysid}; |
|
$doctype->system_id ($token->{system_identifier}) |
|
|
if defined $token->{system_identifier}; |
|
| 301 |
|
|
| 302 |
## TODO: internal_subset |
## TODO: internal_subset |
| 303 |
|
|
| 304 |
$self->{document}->append_child ($doctype); |
$self->{document}->append_child ($doctype); |
| 305 |
|
|
| 306 |
$self->{insertion_mode} = BEFORE_ROOT_ELEMENT_IM; |
$self->{ge} = {}; |
| 307 |
|
|
| 308 |
|
## XML5: No "has internal subset" flag. |
| 309 |
|
if ($token->{has_internal_subset}) { |
| 310 |
|
$self->{doctype} = $doctype; |
| 311 |
|
$self->{insertion_mode} = IN_SUBSET_IM; |
| 312 |
|
} else { |
| 313 |
|
$self->{insertion_mode} = BEFORE_ROOT_ELEMENT_IM; |
| 314 |
|
} |
| 315 |
$token = $self->_get_next_token; |
$token = $self->_get_next_token; |
| 316 |
return; |
return; |
| 317 |
} elsif ($token->{type} == START_TAG_TOKEN or |
} elsif ($token->{type} == START_TAG_TOKEN or |
| 430 |
$el->set_user_data (manakai_source_column => $token->{column}); |
$el->set_user_data (manakai_source_column => $token->{column}); |
| 431 |
|
|
| 432 |
my $has_attr; |
my $has_attr; |
| 433 |
for my $attr_name (sort {$a cmp $b} keys %{$token->{attributes}}) { |
for my $attr_name (sort {$token->{attributes}->{$a}->{index} <=> |
| 434 |
|
$token->{attributes}->{$b}->{index}} |
| 435 |
|
keys %{$token->{attributes}}) { |
| 436 |
my $ns; |
my $ns; |
| 437 |
my ($p, $l) = split /:/, $attr_name, 2; |
my ($p, $l) = split /:/, $attr_name, 2; |
| 438 |
|
|
| 453 |
} |
} |
| 454 |
|
|
| 455 |
if ($has_attr->{defined $ns ? $ns : ''}->{$l}) { |
if ($has_attr->{defined $ns ? $ns : ''}->{$l}) { |
| 456 |
## NOTE: Attributes are sorted as Unicode characters (not |
$ns = undef; |
| 457 |
## code units) of their names, for stable output. |
($p, $l) = (undef, $attr_name); |
|
|
|
|
## TODO: Should be sorted by source order? |
|
|
$self->{parse_error}->(level => $self->{level}->{must}, type => 'duplicate ns attr', |
|
|
token => $token, |
|
|
value => $attr_name); |
|
|
next; |
|
| 458 |
} else { |
} else { |
| 459 |
$has_attr->{defined $ns ? $ns : ''}->{$l} = 1; |
$has_attr->{defined $ns ? $ns : ''}->{$l} = 1; |
| 460 |
} |
} |
| 611 |
$el->set_user_data (manakai_source_column => $token->{column}); |
$el->set_user_data (manakai_source_column => $token->{column}); |
| 612 |
|
|
| 613 |
my $has_attr; |
my $has_attr; |
| 614 |
for my $attr_name (sort {$a cmp $b} keys %{$token->{attributes}}) { |
for my $attr_name (sort {$token->{attributes}->{$a}->{index} <=> |
| 615 |
|
$token->{attributes}->{$b}->{index}} |
| 616 |
|
keys %{$token->{attributes}}) { |
| 617 |
my $ns; |
my $ns; |
| 618 |
my ($p, $l) = split /:/, $attr_name, 2; |
my ($p, $l) = split /:/, $attr_name, 2; |
| 619 |
|
|
| 634 |
} |
} |
| 635 |
|
|
| 636 |
if ($has_attr->{defined $ns ? $ns : ''}->{$l}) { |
if ($has_attr->{defined $ns ? $ns : ''}->{$l}) { |
| 637 |
## NOTE: Attributes are sorted as Unicode characters (not |
$ns = undef; |
| 638 |
## code units) of their names, for stable output. |
($p, $l) = (undef, $attr_name); |
|
|
|
|
## TODO: Should be sorted by source order? |
|
|
$self->{parse_error}->(level => $self->{level}->{must}, type => 'duplicate ns attr', |
|
|
token => $token, |
|
|
value => $attr_name); |
|
|
next; |
|
| 639 |
} else { |
} else { |
| 640 |
$has_attr->{defined $ns ? $ns : ''}->{$l} = 1; |
$has_attr->{defined $ns ? $ns : ''}->{$l} = 1; |
| 641 |
} |
} |
| 808 |
} # B |
} # B |
| 809 |
} # _tree_after_root_element |
} # _tree_after_root_element |
| 810 |
|
|
| 811 |
|
sub _tree_in_subset ($) { |
| 812 |
|
my $self = shift; |
| 813 |
|
|
| 814 |
|
B: while (1) { |
| 815 |
|
if ($token->{type} == COMMENT_TOKEN) { |
| 816 |
|
## Ignore the token. |
| 817 |
|
|
| 818 |
|
## Stay in the state. |
| 819 |
|
$token = $self->_get_next_token; |
| 820 |
|
next B; |
| 821 |
|
} elsif ($token->{type} == ELEMENT_TOKEN) { |
| 822 |
|
unless ($self->{doctype}->get_element_type_definition_node |
| 823 |
|
($token->{name})) { |
| 824 |
|
my $node = $self->{document}->create_element_type_definition |
| 825 |
|
($token->{name}); |
| 826 |
|
$node->set_user_data (manakai_source_line => $token->{line}); |
| 827 |
|
$node->set_user_data (manakai_source_column => $token->{column}); |
| 828 |
|
|
| 829 |
|
$node->content_model_text (join '', @{$token->{content}}) |
| 830 |
|
if $token->{content}; |
| 831 |
|
|
| 832 |
|
$self->{doctype}->set_element_type_definition_node ($node); |
| 833 |
|
} else { |
| 834 |
|
## TODO: ... |
| 835 |
|
|
| 836 |
|
} |
| 837 |
|
|
| 838 |
|
## Stay in the mode. |
| 839 |
|
$token = $self->_get_next_token; |
| 840 |
|
next B; |
| 841 |
|
} elsif ($token->{type} == ATTLIST_TOKEN) { |
| 842 |
|
my $ed = $self->{doctype}->get_element_type_definition_node |
| 843 |
|
($token->{name}); |
| 844 |
|
unless ($ed) { |
| 845 |
|
$ed = $self->{document}->create_element_type_definition |
| 846 |
|
($token->{name}); |
| 847 |
|
$ed->set_user_data (manakai_source_line => $token->{line}); |
| 848 |
|
$ed->set_user_data (manakai_source_column => $token->{column}); |
| 849 |
|
$self->{doctype}->set_element_type_definition_node ($ed); |
| 850 |
|
} |
| 851 |
|
|
| 852 |
|
for my $at (@{$token->{attrdefs}}) { |
| 853 |
|
unless ($ed->get_attribute_definition_node ($at->{name})) { |
| 854 |
|
my $node = $self->{document}->create_attribute_definition |
| 855 |
|
($at->{name}); |
| 856 |
|
$node->set_user_data (manakai_source_line => $at->{line}); |
| 857 |
|
$node->set_user_data (manakai_source_column => $at->{column}); |
| 858 |
|
|
| 859 |
|
my $type = defined $at->{type} ? { |
| 860 |
|
CDATA => 1, ID => 2, IDREF => 3, IDREFS => 4, ENTITY => 5, |
| 861 |
|
ENTITIES => 6, NMTOKEN => 7, NMTOKENS => 8, NOTATION => 9, |
| 862 |
|
}->{$at->{type}} : 10; |
| 863 |
|
if (defined $type) { |
| 864 |
|
$node->declared_type ($type); |
| 865 |
|
} else { |
| 866 |
|
$self->{parse_error}->(level => $self->{level}->{must}, type => 'unknown declared type', ## TODO: type |
| 867 |
|
value => $at->{type}, |
| 868 |
|
token => $at); |
| 869 |
|
} |
| 870 |
|
|
| 871 |
|
push @{$node->allowed_tokens}, @{$at->{tokens}}; |
| 872 |
|
|
| 873 |
|
my $default = defined $at->{default} ? { |
| 874 |
|
FIXED => 1, REQUIRED => 2, IMPLIED => 3, |
| 875 |
|
}->{$at->{default}} : 4; |
| 876 |
|
if (defined $default) { |
| 877 |
|
$node->default_type ($default); |
| 878 |
|
if (defined $at->{value}) { |
| 879 |
|
if ($default == 1 or $default == 4) { |
| 880 |
|
# |
| 881 |
|
} elsif (length $at->{value}) { |
| 882 |
|
$self->{parse_error}->(level => $self->{level}->{must}, type => 'default value not allowed', ## TODO: type |
| 883 |
|
token => $at); |
| 884 |
|
} |
| 885 |
|
} else { |
| 886 |
|
if ($default == 1 or $default == 4) { |
| 887 |
|
$self->{parse_error}->(level => $self->{level}->{must}, type => 'default value not provided', ## TODO: type |
| 888 |
|
token => $at); |
| 889 |
|
} |
| 890 |
|
} |
| 891 |
|
} else { |
| 892 |
|
$self->{parse_error}->(level => $self->{level}->{must}, type => 'unknown default type', ## TODO: type |
| 893 |
|
value => $at->{default}, |
| 894 |
|
token => $at); |
| 895 |
|
} |
| 896 |
|
|
| 897 |
|
$node->text_content ($at->{value}) if defined $at->{value}; |
| 898 |
|
|
| 899 |
|
$ed->set_attribute_definition_node ($node); |
| 900 |
|
} else { |
| 901 |
|
## TODO: ... |
| 902 |
|
} |
| 903 |
|
} # $at |
| 904 |
|
|
| 905 |
|
## Stay in the mode. |
| 906 |
|
$token = $self->_get_next_token; |
| 907 |
|
next B; |
| 908 |
|
} elsif ($token->{type} == GENERAL_ENTITY_TOKEN) { |
| 909 |
|
## TODO: predefined entity names |
| 910 |
|
|
| 911 |
|
unless ($self->{ge}->{$token->{name}.';'}) { |
| 912 |
|
## For parser. |
| 913 |
|
$self->{ge}->{$token->{name}.';'} = $token; |
| 914 |
|
if (defined $token->{value} and |
| 915 |
|
$token->{value} !~ /[&<]/) { |
| 916 |
|
$token->{only_text} = 1; |
| 917 |
|
} |
| 918 |
|
|
| 919 |
|
## For DOM. |
| 920 |
|
if (defined $token->{notation}) { |
| 921 |
|
my $node = $self->{document}->create_general_entity ($token->{name}); |
| 922 |
|
$node->set_user_data (manakai_source_line => $token->{line}); |
| 923 |
|
$node->set_user_data (manakai_source_column => $token->{column}); |
| 924 |
|
|
| 925 |
|
$node->public_id ($token->{pubid}); # may be undef |
| 926 |
|
$node->system_id ($token->{sysid}); # may be undef |
| 927 |
|
$node->notation_name ($token->{notation}); |
| 928 |
|
|
| 929 |
|
$self->{doctype}->set_general_entity_node ($node); |
| 930 |
|
} |
| 931 |
|
} else { |
| 932 |
|
## TODO: ... |
| 933 |
|
|
| 934 |
|
} |
| 935 |
|
|
| 936 |
|
## Stay in the mode. |
| 937 |
|
$token = $self->_get_next_token; |
| 938 |
|
next B; |
| 939 |
|
} elsif ($token->{type} == PARAMETER_ENTITY_TOKEN) { |
| 940 |
|
unless ($self->{pe}->{$token->{name}}) { |
| 941 |
|
## For parser. |
| 942 |
|
$self->{pe}->{$token->{name}} = $token; |
| 943 |
|
} else { |
| 944 |
|
## TODO: ... |
| 945 |
|
} |
| 946 |
|
|
| 947 |
|
## Stay in the mode. |
| 948 |
|
$token = $self->_get_next_token; |
| 949 |
|
next B; |
| 950 |
|
} elsif ($token->{type} == NOTATION_TOKEN) { |
| 951 |
|
unless ($self->{doctype}->get_notation_node |
| 952 |
|
($token->{name})) { |
| 953 |
|
my $node = $self->{document}->create_notation ($token->{name}); |
| 954 |
|
$node->set_user_data (manakai_source_line => $token->{line}); |
| 955 |
|
$node->set_user_data (manakai_source_column => $token->{column}); |
| 956 |
|
|
| 957 |
|
$node->public_id ($token->{pubid}); # may be undef |
| 958 |
|
$node->system_id ($token->{sysid}); # may be undef |
| 959 |
|
|
| 960 |
|
$self->{doctype}->set_notation_node ($node); |
| 961 |
|
} else { |
| 962 |
|
## TODO: ... |
| 963 |
|
|
| 964 |
|
} |
| 965 |
|
|
| 966 |
|
## Stay in the mode. |
| 967 |
|
$token = $self->_get_next_token; |
| 968 |
|
next B; |
| 969 |
|
} elsif ($token->{type} == PI_TOKEN) { |
| 970 |
|
my $pi = $self->{document}->create_processing_instruction |
| 971 |
|
($token->{target}, $token->{data}); |
| 972 |
|
$self->{doctype}->append_child ($pi); |
| 973 |
|
## TODO: line/col |
| 974 |
|
|
| 975 |
|
## Stay in the mode. |
| 976 |
|
$token = $self->_get_next_token; |
| 977 |
|
next B; |
| 978 |
|
} elsif ($token->{type} == END_OF_DOCTYPE_TOKEN) { |
| 979 |
|
$self->{insertion_mode} = BEFORE_ROOT_ELEMENT_IM; |
| 980 |
|
$token = $self->_get_next_token; |
| 981 |
|
return; |
| 982 |
|
} elsif ($token->{type} == ABORT_TOKEN) { |
| 983 |
|
return; |
| 984 |
|
} else { |
| 985 |
|
die "$0: XML parser subset im: Unknown token type $token->{type}"; |
| 986 |
|
} |
| 987 |
|
} # B |
| 988 |
|
|
| 989 |
|
} # _tree_in_subset |
| 990 |
|
|
| 991 |
} |
} |
| 992 |
|
|
| 993 |
1; |
1; |