Skip to content

Commit

Permalink
Merge pull request #9 from Kazakbay/without_namespaces
Browse files Browse the repository at this point in the history
Add the ability to parse xml without namespaces/key prefix
  • Loading branch information
nhu313 authored Nov 27, 2017
2 parents 1db1758 + 97a59d5 commit 9683414
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 20 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,38 @@ Calling parse on the xml will produce
value: [%{attr: [short_name: "yah"], name: :title, value: ["Yahoo"]},
%{attr: [], name: :"title:content", value: ["Bing"]}]}]
```
### Parsing without namespaces(key prefix)
```elixir
xml = "<m:return xsi:type="d4p1:Answer">
<d4p1:Title> Title </d4p1:Title>
<d4p1:Description> Description </d4p1:Description>
</m:return>"

Quinn.parse(xml, %{strip_namespaces: true})
```

Calling parse on the xml will produce
```elixir
[%{attr: ["xsi:type": "d4p1:Answer"],
name: :return,
value: [%{attr: [], name: :title, value: ["Title"]},
%{attr: [], name: :description, value: ["Description"]}]}]
```

### Parsing comments
```elixir
xml = ~s(<head><title short_name = "yah">Yahoo</title><!--- <test pattern="SECAM" /><test pattern="NTSC" /> --></head>)
result = Quinn.parse(xml, %{comments: true})
```
The xml above will give you this. Note the name is `comments`.

```elixir
[%{attr: [],
name: :head,
value: [%{attr: [short_name: "yah"], name: :title, value: ["Yahoo"]},
%{attr: [], name: :comments, value: ~s(- <test pattern="SECAM" /><test pattern="NTSC" />)}]}]
```

# Finding nodes

Suppose you want to find all the body nodes from this structure:
Expand Down
4 changes: 2 additions & 2 deletions lib/quinn.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Quinn do

def parse(xml) do
Quinn.XmlParser.parse(xml)
def parse(xml, strip_namespaces \\ nil) do
Quinn.XmlParser.parse(xml, strip_namespaces)
end

def find(node, node_names) do
Expand Down
42 changes: 26 additions & 16 deletions lib/xml_parser/xml_parser.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
defmodule Quinn.XmlParser do

def parse(xml) do
def parse(xml, options \\ %{}) do
:erlang.bitstring_to_list(xml)
|> :xmerl_scan.string
|> elem(0)
|> parse_record
|> parse_record(options)
end

defp combine_values([]), do: []
Expand All @@ -17,12 +17,13 @@ defmodule Quinn.XmlParser do
end
end

defp parse_record({:xmlElement, name, _, _, _, _, _, attributes, elements, _, _, _}) do
value = combine_values(parse_record(elements))
defp parse_record({:xmlElement, name, _, _, _, _, _, attributes, elements, _, _, _}, options) do
value = combine_values(parse_record(elements, options))
name = parse_name(name, options)
[%{name: name, attr: parse_attribute(attributes), value: value}]
end

defp parse_record({:xmlText, _, _, _, value, _}) do
defp parse_record({:xmlText, _, _, _, value, _}, _) do
string_value = String.strip(to_string(value))
if (String.length(string_value) > 0) do
[string_value]
Expand All @@ -31,16 +32,18 @@ defmodule Quinn.XmlParser do
end
end

defp parse_record({:xmlComment, _, _, _, _value}) do
[]
defp parse_record({:xmlComment, _, _, _, value}, options) do
if options[:comments] do
[%{name: :comments, attr: [], value: String.strip(to_string(value))}]
else
[]
end
end

defp parse_record([]), do: []
defp parse_record([], _), do: []

defp parse_record([element]), do: parse_record(element)

defp parse_record([head | tail]) do
parse_record(head) ++ parse_record(tail)
defp parse_record([head | tail], options) do
parse_record(head, options) ++ parse_record(tail, options)
end

defp parse_attribute([]), do: []
Expand All @@ -49,11 +52,18 @@ defmodule Quinn.XmlParser do
[{name, to_string(value)}]
end

defp parse_attribute([attribute]) do
parse_attribute(attribute)
end

defp parse_attribute([head | tail]) do
parse_attribute(head) ++ parse_attribute(tail)
end

defp parse_name(name, %{strip_namespaces: true}) do
name
|> to_string
|> String.split(":")
|> List.last
|> Macro.underscore
|> String.to_atom
end

defp parse_name(name, _), do: name
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Quinn.Mixfile do
def project do
[
app: :quinn,
version: "1.0.2",
version: "1.1.0",
elixir: "~> 1.3",
deps: deps(),
description: description(),
Expand Down
25 changes: 24 additions & 1 deletion test/xml_parser/xml_parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ defmodule Quinn.XmlParserTest do
assert expected == Quinn.parse(xml)
end

test "comments" do
test "ignore comments" do
xml = "<head><title short_name = \"yah\">Yahoo</title><title:content>Bing</title:content><!-- foo --></head>"
expected = [%{attr: [],
name: :head,
Expand All @@ -61,6 +61,16 @@ defmodule Quinn.XmlParserTest do
assert expected == Quinn.parse(xml)
end

test "parse comments" do
xml = ~s(<head><title short_name = "yah">Yahoo</title><!--- <test pattern="SECAM" /><test pattern="NTSC" /> --></head>)
comments = ~s(- <test pattern="SECAM" /><test pattern="NTSC" />)
expected = [%{attr: [],
name: :head,
value: [%{attr: [short_name: "yah"], name: :title, value: ["Yahoo"]},
%{attr: [], name: :comments, value: comments}]}]
assert expected == Quinn.parse(xml, %{comments: true})
end

test "parse small rss feed" do
[title] = File.read!("test/xml_parser/fixture/rss_small.xml")
|> Quinn.parse
Expand All @@ -81,4 +91,17 @@ defmodule Quinn.XmlParserTest do
|> Quinn.find([:entry, :title])
assert hd(title.value) =~ "Wearing The Pants"
end

test "parse without namespace" do
xml = ~s(<m:return xsi:type="d4p1:Answer"><d4p1:Title> Title </d4p1:Title><d4p1:Description> Description </d4p1:Description></m:return>)

expected = [%{attr: ["xsi:type": "d4p1:Answer"],
name: :return,
value: [%{attr: [], name: :title, value: ["Title"]},
%{attr: [],
name: :description,
value: ["Description"]}]}]

assert expected == Quinn.parse(xml, %{strip_namespaces: true})
end
end

0 comments on commit 9683414

Please sign in to comment.