def create_patch_from_children(before_node, after_node)
      operations = []
      identity_map = {}
      inverted_identity_map = {}

      ::Diff::LCS.sdiff(before_node.children.map(&:to_s), after_node.children.map(&:to_s)).each do |element|
        type, before, after = *element
        if type == "="
          before_child = before_node.children[before[0]]
          after_child = after_node.children[after[0]]
          identity_map[before_child] = after_child
          inverted_identity_map[after_child] = before_child
        end
      end

      # Partial matching
      before_node.children.each do |before_child|
        if identity_map[before_child]
          next
        end
        after_node.children.each do |after_child|
          case
          when identity_map[before_child]
            break
          when inverted_identity_map[after_child]
          when before_child.text?
            if after_child.text?
              identity_map[before_child] = after_child
              inverted_identity_map[after_child] = before_child
              operations << ::Markdiff::Operations::TextDiffOperation.new(target_node: before_child, after_node: after_child)
            end
          when before_child.name == after_child.name
            if before_child.attributes == after_child.attributes
              identity_map[before_child] = after_child
              inverted_identity_map[after_child] = before_child
              operations += create_patch(before_child, after_child)
            elsif detect_href_difference(before_child, after_child)
              operations << ::Markdiff::Operations::AddDataBeforeHrefOperation.new(after_href: after_child["href"], target_node: before_child)
              identity_map[before_child] = after_child
              inverted_identity_map[after_child] = before_child
              operations += create_patch(before_child, after_child)
            end
          when detect_heading_level_difference(before_child, after_child)
            operations << ::Markdiff::Operations::AddDataBeforeTagNameOperation.new(after_tag_name: after_child.name, target_node: before_child)
            identity_map[before_child] = after_child
            inverted_identity_map[after_child] = before_child
          end
        end
      end

      before_node.children.each do |before_child|
        unless identity_map[before_child]
          operations << ::Markdiff::Operations::RemoveOperation.new(target_node: before_child)
        end
      end

      after_node.children.each do |after_child|
        unless inverted_identity_map[after_child]
          right_node = after_child.next_sibling
          loop do
            case
            when inverted_identity_map[right_node]
              operations << ::Markdiff::Operations::AddPreviousSiblingOperation.new(inserted_node: after_child, target_node: inverted_identity_map[right_node])
              break
            when right_node.nil?
              operations << ::Markdiff::Operations::AddChildOperation.new(inserted_node: after_child, target_node: before_node)
              break
            else
              right_node = right_node.next_sibling
            end
          end
        end
      end

      operations
    end
def create_patch_from_children(before_node, after_node)
      operations = []
      identity_map = {}
      inverted_identity_map = {}

      ::Diff::LCS.sdiff(before_node.children.map(&:to_s), after_node.children.map(&:to_s)).each do |element|
        type, before, after = *element
        if type == "="
          before_child = before_node.children[before[0]]
          after_child = after_node.children[after[0]]
          identity_map[before_child] = after_child
          inverted_identity_map[after_child] = before_child
        end
      end

      # Partial matching
      before_node.children.each do |before_child|
        if identity_map[before_child]
          next
        end
        after_node.children.each do |after_child|
          case
          when identity_map[before_child]
            break
          when inverted_identity_map[after_child]
          when before_child.text?
            if after_child.text?
              identity_map[before_child] = after_child
              inverted_identity_map[after_child] = before_child
              operations << ::Markdiff::Operations::TextDiffOperation.new(target_node: before_child, after_node: after_child)
            end
          when before_child.name == after_child.name
            if before_child.attributes == after_child.attributes
              identity_map[before_child] = after_child
              inverted_identity_map[after_child] = before_child
              operations += create_patch(before_child, after_child)
            elsif detect_href_difference(before_child, after_child)
              operations << ::Markdiff::Operations::AddDataBeforeHrefOperation.new(after_href: after_child["href"], target_node: before_child)
              identity_map[before_child] = after_child
              inverted_identity_map[after_child] = before_child
              operations += create_patch(before_child, after_child)
            end
          when detect_heading_level_difference(before_child, after_child)
            operations << ::Markdiff::Operations::AddDataBeforeTagNameOperation.new(after_tag_name: after_child.name, target_node: before_child)
            identity_map[before_child] = after_child
            inverted_identity_map[after_child] = before_child
          end
        end
      end

      before_node.children.each do |before_child|
        unless identity_map[before_child]
          operations << ::Markdiff::Operations::RemoveOperation.new(target_node: before_child)
        end
      end

      after_node.children.each do |after_child|
        unless inverted_identity_map[after_child]
          right_node = after_child.next_sibling
          loop do
            case
            when inverted_identity_map[right_node]
              operations << ::Markdiff::Operations::AddPreviousSiblingOperation.new(inserted_node: after_child, target_node: inverted_identity_map[right_node])
              break
            when right_node.nil?
              operations << ::Markdiff::Operations::AddChildOperation.new(inserted_node: after_child, target_node: before_node)
              break
            else
              right_node = right_node.next_sibling
            end
          end
        end
      end

      operations
    end
1. Create identity map and collect patches from descendants
   1-1. Detect exact-matched nodes
   1-2. Detect partial-matched nodes and recursively walk through its children
 2. Create remove operations from identity map
 3. Create insert operations from identity map
 4. Return operations as a patch

 @param [Nokogiri::XML::Node] before_node
 @param [Nokogiri::XML::Node] after_node
 @return [Array<Markdiff::Operations::Base>] operations