diff --git a/lib/feed_reader/parser.ex b/lib/feed_reader/parser.ex index d1e4cf3..b4a69fc 100644 --- a/lib/feed_reader/parser.ex +++ b/lib/feed_reader/parser.ex @@ -337,15 +337,99 @@ defmodule FeedReader.Parser do defp flush_entities({_mode, pending}), do: [pending] defp normalize_attribute_quotes(input) do - Stream.map(input, fn chunk -> - Regex.replace( - ~r/(=\")([^\"]*)(\")([^\"]*)(\")(\")(?=\s*(?:\/>|>))/, - chunk, - "\\1\\2"\\4"\\6" - ) - end) + Stream.transform( + input, + fn -> <<>> end, + fn chunk, pending -> + {output, pending} = scan_attribute_markup(pending <> chunk, []) + {if(output == [], do: [], else: [IO.iodata_to_binary(Enum.reverse(output))]), pending} + end, + fn + <<>> -> [] + pending -> [pending] + end + ) end + defp scan_attribute_markup(<<>>, output), do: {output, <<>>} + + defp scan_attribute_markup(data, output) do + case :binary.match(data, "<") do + :nomatch -> + {[data | output], <<>>} + + {position, 1} when position > 0 -> + {prefix, rest} = :erlang.split_binary(data, position) + scan_attribute_markup(rest, [prefix | output]) + + {0, 1} -> + case markup_end(data) do + :incomplete -> {output, data} + {markup, rest} -> scan_attribute_markup(rest, [repair_markup_quotes(markup) | output]) + end + end + end + + defp markup_end(<<"> = data), do: special_markup_end(data, "]]>") + defp markup_end(<<"") + + defp markup_end(data) do + case :binary.match(data, ">") do + :nomatch -> :incomplete + {position, 1} -> :erlang.split_binary(data, position + 1) + end + end + + defp special_markup_end(data, closing) do + case :binary.match(data, closing) do + :nomatch -> :incomplete + {position, length} -> :erlang.split_binary(data, position + length) + end + end + + defp repair_markup_quotes(<<"> = markup), do: markup + defp repair_markup_quotes(<<"