Skip to content

Instantly share code, notes, and snippets.

@ckampfe
Created March 4, 2025 19:03
Show Gist options
  • Save ckampfe/b0089b046bc2041e521b842f7002d34a to your computer and use it in GitHub Desktop.
Save ckampfe/b0089b046bc2041e521b842f7002d34a to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.clojars.ckampfe</groupId>
<artifactId>fp</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>ckampfe/fp</name>
<description>FIXME: my new application.</description>
<url>https://github.com/ckampfe/fp</url>
<licenses>
<license>
<name>Eclipse Public License</name>
<url>http://www.eclipse.org/legal/epl-v10.html</url>
</license>
</licenses>
<developers>
<developer>
<name>Clark</name>
</developer>
</developers>
<scm>
<url>https://github.com/ckampfe/fp</url>
<connection>scm:git:git://github.com/ckampfe/fp.git</connection>
<developerConnection>scm:git:ssh://[email protected]/ckampfe/fp.git</developerConnection>
<tag>v0.1.0-SNAPSHOT</tag>
</scm>
<dependencies>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.11.1</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
</build>
<repositories>
<repository>
<id>clojars</id>
<url>https://repo.clojars.org/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>clojars</id>
<name>Clojars repository</name>
<url>https://clojars.org/repo</url>
</repository>
</distributionManagement>
</project>
defmodule Saxml do
import Kernel, except: [get_in: 2, get_in: 1]
defmacro sigil_l(s, []) do
{:list, s}
end
defmacro get_in(m, [key]) do
case key do
# an attribute
"@" <> _rest ->
quote do
case unquote(m) do
%{unquote(key) => v} ->
v
_ ->
nil
end
end
# a "list" designator
{:sigil_l, _meta1, [{:<<>>, _meta2, [s]}, []]} ->
quote do
Enum.map(unquote(m), fn %{unquote(s) => %{"content" => v}} ->
v
end)
end
{variable_name, _meta, _} when is_atom(variable_name) ->
quote do
case unquote(m) do
%{^unquote(key) => %{"content" => v}} ->
v
_ ->
nil
end
end
# any normal element lookup
_k ->
quote do
case unquote(m) do
%{unquote(key) => %{"content" => v}} ->
v
_ ->
nil
end
end
end
end
defmacro get_in(m, [key, next_key | keys]) do
case key do
# an attribute
"@" <> _rest ->
quote do
case unquote(m) do
%{unquote(key) => v} ->
Saxml.get_in(v, unquote(keys))
_ ->
nil
end
end
{variable_name, _meta, _} when is_atom(variable_name) ->
case next_key do
# the next key is an attribute
"@" <> _rest ->
quote do
case unquote(m) do
%{^unquote(key) => v} ->
Saxml.get_in(v, unquote([next_key | keys]))
_ ->
nil
end
end
# the next key is a list designator
{:sigil_l, _meta1, [{:<<>>, _meta2, [s]}, []]} ->
quote do
case unquote(m) do
%{^unquote(key) => l} when is_list(l) ->
Enum.map(l, fn %{"content" => %{unquote(s) => %{"content" => v}}} ->
v
end)
_ ->
nil
end
end
# the next key is a normal element lookup
_non_attribute ->
quote do
case unquote(m) do
%{^unquote(key) => %{"content" => content}} ->
Saxml.get_in(content, unquote([next_key | keys]))
_ ->
nil
end
end
end
# any normal element lookup
_key ->
case next_key do
# the next key is an attribute
"@" <> _rest ->
quote do
case unquote(m) do
%{unquote(key) => v} ->
Saxml.get_in(v, unquote([next_key | keys]))
_ ->
nil
end
end
# the next key is a list designator
{:sigil_l, _meta1, [{:<<>>, _meta2, [s]}, []]} ->
quote do
case unquote(m) do
%{unquote(key) => l} when is_list(l) ->
Enum.map(l, fn %{"content" => %{unquote(s) => %{"content" => v}}} ->
v
end)
_ ->
nil
end
end
# the next key is a normal element lookup
_non_attribute ->
quote do
case unquote(m) do
%{unquote(key) => %{"content" => content}} ->
Saxml.get_in(content, unquote([next_key | keys]))
_ ->
nil
end
end
end
end
end
end
defmodule SaxmlTest do
use ExUnit.Case
doctest Saxml
require Saxml
setup do
file = File.read!("pom.xml")
{:ok, m} =
SAXMap.from_string(file, ignore_attribute: {false, "@"})
# |> IO.inspect()
[m: m]
end
test "greets the world", %{m: m} do
assert "http://maven.apache.org/POM/4.0.0" ==
Saxml.get_in(m, ["project", "@xmlns"])
assert "http://www.w3.org/2001/XMLSchema-instance" ==
Saxml.get_in(m, ["project", "@xmlns:xsi"])
assert "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" ==
Saxml.get_in(m, ["project", "@xsi:schemaLocation"])
assert "4.0.0" == Saxml.get_in(m, ["project", "modelVersion"])
assert "net.clojars.ckampfe" == Saxml.get_in(m, ["project", "groupId"])
assert "fp" == Saxml.get_in(m, ["project", "artifactId"])
assert "0.1.0-SNAPSHOT" == Saxml.get_in(m, ["project", "version"])
assert "ckampfe/fp" == Saxml.get_in(m, ["project", "name"])
assert "FIXME: my new application." == Saxml.get_in(m, ["project", "description"])
assert "https://github.com/ckampfe/fp" == Saxml.get_in(m, ["project", "url"])
assert "Eclipse Public License" == Saxml.get_in(m, ["project", "licenses", "license", "name"])
assert "http://www.eclipse.org/legal/epl-v10.html" ==
Saxml.get_in(m, ["project", "licenses", "license", "url"])
assert "Clark" == Saxml.get_in(m, ["project", "developers", "developer", "name"])
assert "https://github.com/ckampfe/fp" == Saxml.get_in(m, ["project", "scm", "url"])
assert "scm:git:git://github.com/ckampfe/fp.git" ==
Saxml.get_in(m, ["project", "scm", "connection"])
assert "scm:git:ssh://[email protected]/ckampfe/fp.git" ==
Saxml.get_in(m, ["project", "scm", "developerConnection"])
assert "v0.1.0-SNAPSHOT" == Saxml.get_in(m, ["project", "scm", "tag"])
assert "org.clojure" ==
Saxml.get_in(m, ["project", "dependencies", "dependency", "groupId"])
assert "clojure" ==
Saxml.get_in(m, ["project", "dependencies", "dependency", "artifactId"])
assert "1.11.1" ==
Saxml.get_in(m, ["project", "dependencies", "dependency", "version"])
assert "src" == Saxml.get_in(m, ["project", "build", "sourceDirectory"])
# assert [
# %{
# "id" => %{"content" => "clojars"},
# "url" => %{"content" => "https://repo.clojars.org/"}
# },
# %{
# "id" => %{"content" => "sonatype"},
# "url" => %{"content" => "https://oss.sonatype.org/content/repositories/snapshots/"}
# }
# ] ==
# Saxml.get_in(m, ["project", "repositories", "repository"])
assert "clojars" == Saxml.get_in(m, ["project", "distributionManagement", "repository", "id"])
assert "Clojars repository" ==
Saxml.get_in(m, ["project", "distributionManagement", "repository", "name"])
assert "https://clojars.org/repo" ==
Saxml.get_in(m, ["project", "distributionManagement", "repository", "url"])
end
test "lists", %{m: m} do
assert [
"clojars",
"sonatype"
] ==
Saxml.get_in(m, ["project", "repositories", "repository", ~l"id"])
assert [
"https://repo.clojars.org/",
"https://oss.sonatype.org/content/repositories/snapshots/"
] ==
Saxml.get_in(m, ["project", "repositories", "repository", ~l"url"])
end
test "variables", %{m: m} do
version_element = "version"
assert "1.11.1" ==
Saxml.get_in(m, ["project", "dependencies", "dependency", version_element])
dependencies_element = "dependencies"
assert "1.11.1" ==
Saxml.get_in(m, ["project", dependencies_element, "dependency", version_element])
end
test "variables lists", %{m: m} do
respositories_tag = "repositories"
assert [
"clojars",
"sonatype"
] ==
Saxml.get_in(m, ["project", respositories_tag, "repository", ~l"id"])
# this does not work, I do not know if it can be made to work,
# since the macro would need to be able to see through the variable,
# to see that it is a list designator
#
# id_tag = ~l"id"
# assert [
# "clojars",
# "sonatype"
# ] ==
# Saxml.get_in(m, ["project", respositories_tag, "repository", id_tag])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment