1
votes

I am trying to pattern match these values which are returned by running mochixpath. The pattern is clearly [elemName, htmlAttrs, children], but what I really need from the following values is UserNameA and "This is a message"

[{"tr", [{"bgcolor", "White"}],
  [{"td", [{"class", "Topic"}],
   [{"div", [],
    [{"a", [{"class", "lnkUserName"}, {"href", "/users/prof.aspx?u=27149"}],
      ["UserNameA"]
    }]
 }]},
 {"img", [{"alt", ""}, {"src", "/Images/Icons/userIcon.gif"}], []},     
 {"td", [{"class", "bHeader"}],
    [{"div", [{"style", "float:left;width:77%;"}],[
        {"a", [{"class", "PostDisplay"}],
          ["This is a message"]}]
    }]
 }]

Essentially I'm using the parsed xml from the output of the xpath to get the username and the message they sent. I am very new to elixir and the concept of pattern matching so any help is greatly appreciated.

2
If you're looking for an answer in Elixir you probably want to remove the Erlang tag. - Onorio Catenacci

2 Answers

0
votes

The curly and square brackets are not balanced in your example. I guess it is missing a }] at the end.

It seems that the deepness of the expression may vary, so you have to explore it recursively. The code belows does it, assuming that you will find the information in type "a" elements:

-module (ext).
-compile([export_all]).


extL(L) -> extL(L,[]).

extL([],R) -> R;
extL([H|Q],R) -> extL(Q, extT(H) ++ R).

extT({"a",PropL,L}) ->
    case proplists:get_value("class",PropL) of
        "lnkUserName" -> [{user_name, hd(L)}];
        "PostDisplay" -> [{post_display,hd(L)}];
        _ -> extL(L,[])
    end;
extT({_,_,L}) -> extL(L,[]).

with your example it returns the proplist [{post_display,"This is a message"},{user_name,"UserNameA"}]

0
votes

Something is wrong with the output, because it spits syntax error, when I copy it to console, so I'll assume that you have tr, with td, img and other td inside.

Pattern matching can be used for unwrapping this way. Lets say, you have your whole data in variable Data, you can extract the contents with:

[TR] = Data,
{_Name, _Attrs, Contents} = TR.

Now Contents is again a list of nodes: [Td1, Img, Td2], so you can do:

[Td1, Img, Td2] = Contents.

And so on, until you actually reach your contents. But writing that is pretty tedious and you can use recursion instead. Lets define contents function, that recursively scans the elements.

contents({_Name, _Attrs, Contents}) ->
    case Contents of
        [] -> []; % no contents like in img tag
        [H | T] ->
            case is_tuple(H) of
                % tupe means list of children
                true -> lists:map(fun contents/1, [H | T]);
                % otherwise this must be a string
                _ -> [H | T]
            end
    end.

This will return nested list, but you can at the end run lists:flatten like this:

Values = lists:flatten(contents(Data)).