Parse xml data from a chunk of source string (file stringified for IO on device).
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
class(xml_file), | intent(inout) | :: | self |
XML file handler. |
||
character(len=*), | intent(in) | :: | source_string |
String containing xml data. |
pure subroutine parse_from_string(self, source_string) !< Parse xml data from a chunk of source string (file stringified for IO on device). class(xml_file), intent(inout) :: self !< XML file handler. character(*), intent(in) :: source_string !< String containing xml data. integer(I4P) :: pos, start_pos, end_pos, end_content_pos !< Position indexes. character(:), allocatable :: tag_name !< Tag name buffer. character(:), allocatable :: attributes_str !< Tag attributes string buffer. character(:), allocatable :: tag_content !< Tag content string buffer. integer(I4P) :: current_level !< Nesting level counter. logical :: is_closing_tag !< Sentinel for closing tag. logical :: is_self_closing !< Sentinel for self closing tag. type(xml_tag) :: tag !< XML tag handler. integer(I4P) :: parent_id !< Uniq parent tag ID. integer(I4P), allocatable :: parent_stack(:) !< Stack of parents ID. call self%free pos = 1_I4P current_level = 0_I4P allocate(parent_stack(1)) parent_stack = 0_I4P do while (pos <= len_trim(source_string)) ! next tag start start_pos = index(source_string(pos:), '<') if (start_pos == 0) exit start_pos = pos + start_pos - 1 ! skip comment, XML header if (start_pos + 3 <= len_trim(source_string)) then if (source_string(start_pos:start_pos+3) == '<!--'.or.source_string(start_pos:start_pos+1) == '<?') then end_pos = index(source_string(start_pos+1:), '>') if (end_pos == 0) exit pos = start_pos + end_pos + 1 cycle endif endif ! close current tag end_pos = index(source_string(start_pos:), '>') if (end_pos == 0) exit end_pos = start_pos + end_pos - 1 ! parse tag call parse_tag_name(tag_str = source_string(start_pos:end_pos), & tag_name = tag_name, & attributes_str = attributes_str, & is_closing = is_closing_tag, & is_self_closing = is_self_closing) if (allocated(tag_name)) then if (is_closing_tag) then current_level = current_level - 1 else ! add new tag to XML tags list call tag%free call self%add_tag(tag=tag) current_level = current_level + 1 ! get parent/child id if (current_level>1) then if (parent_stack(current_level-1)>0) then parent_id = parent_stack(current_level-1) call self%add_child(parent_id=parent_stack(current_level - 1), child_id=self%nt) endif elseif (current_level==1) then parent_id = 0_I4P endif ! parent_stack(current_level) = self%nt if (current_level==1) then parent_stack(1) = self%nt else if (current_level>1) parent_stack = [parent_stack(1:current_level-1),self%nt] endif end_content_pos = -1 ! initialize position for self closing tag if (.not.is_self_closing) then ! get tag content call get_tag_content(source=source_string, tag_name=tag_name, start_pos=end_pos + 1, content=tag_content, & end_pos=end_content_pos) endif call self%tag(self%nt)%set(name = tag_name, & sanitize_attributes_value = .true., & pos = [start_pos, end_pos, end_content_pos], & indent = (current_level-1)*2, & is_self_closing = is_self_closing, & id = self%nt, & level = current_level, & parent_id = parent_id, & attributes_stream_alloc = attributes_str, & content_alloc = tag_content) if (is_self_closing) current_level = current_level - 1 endif endif pos = end_pos + 1 enddo endsubroutine parse_from_string