EasterPeanut

EasterPeanut

Nice way to check if iodata is an HTML link?

In a Phoenix template we are trying to check if a Phoenix.HTML.Safe contains iodata that represents an HTML link. Based on whether it’s a link, we want to add a certain class to an element.

We want to check / pattern match on the given input and return true when all the following conditions are met:

  • The input is an “a” tag.
  • The input is only one node / tag.
  • The input can have surrounding whitespace.

Now, to check if the given input is a link, we had the following code:

    defp link?({:safe, [60, "a" | _]}), do: true
    defp link?({:safe, [" " <> _, [60, "a" | _] | _]}), do: true
    defp link?(_), do: false

Example what it should do:

{:safe,
  [
    "         ",
    [60, "a", [[32, "href", 61, 34, "/", 34]], 62, "this is a link", 60, 47, "a", 62],
    "         "
  ]
} 
|> link?()
true

That seemed dirty so we figured it might be better to convert the input by using safe_to_string/1, escape it, and then pattern match or regex on the result.

That still feels tricky, so we now decided to use Floki to do the job, as it looks like a good way to go. However, we are curious as to the alternatives. So, are there any other (maybe simpler) options to achieve this?

Marked As Solved

dimitarvp

dimitarvp

Floki is pretty good but it really depends on what kind of HTML input you are dealing with. Meeseeks works better with malformed HTML soups but it has a Rust compiler dependency (which turned out to be a non-issue even on Windows; Rust’s tooling is really nimble).

I’d say though, sanitize your HTML input heavily + use Floki. Do not concern yourself with parsing performance unless you have to parse megabytes of HTML every few seconds.

Also Liked

chrismccord

chrismccord

Creator of Phoenix

It would be much easier and faster to implement your own link function which adds the class. This wouldn’t catch hard-coded anchor tags, but if it ticks all the requirement boxes you’re looking at a few minutes of work.

OvermindDL1

OvermindDL1

Parsing out the iodata/string definitely seems like the wrong step to do this on to me. Why not just have your template functions return out a tuple structure or so encoding your data then just run a final pass over it before encoding it into eex template format? Personally I have a module that defines just about everything used in my templates from various containers to lots of link types to form handlers and a whole lot more. A lot of building up in that is very just tuple structures and it’s been very easy to use and change. :slight_smile:

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call t...
New
yawaramin
In the Dialyzer docs ( dialyzer — OTP 29.0.2 (dialyzer 6.0.1) ), there is a way to turn off a specific warning for a function: -dialyzer...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31265 143
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52673 488
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement