Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Looping via xmap #31

Open
programisti opened this issue Jun 2, 2016 · 5 comments
Open

Looping via xmap #31

programisti opened this issue Jun 2, 2016 · 5 comments

Comments

@programisti
Copy link

<Query>
        <cars>
            <bmw>
                <specs>
                    <model>5 seriesw</model>
                    <engine>4.4</engine>
                </specs>
            </bmw>
            <bmw>
                <specs>
                    <model>3 seriesw</model>
                    <engine>3.0</engine>
                </specs>
            </bmw>
        </cars>
</Query>

Im parsing this via SweetXml

request_body |> parse |> xmap(
  cars: [
    ~x"//Query/cars"k,
    bmw: [
      ~x"./bmw"kl,
      specs: [
        ~x"./specs"k,
          model: ~x"./model/text()"s,
          engine: ~x"./engin/text()"s
      ]
    ]
  ]
)

I want to get data like this format:

[
  Query: [
   cars: [
     bmw: [ 
        specs: [
          model: "5series"
          engine: 4,4
        ]
    ], 
    bmw: [ 
        specs: [
          model: "5series"
          engine: 4,4
        ]
      ]
    ]
  ]
]

Problem is that I get

[cars: [bmw: [specs: [[model: "5 seriesw", engin: ""]]]]]

Its not looping on Query/cars/*

@programisti programisti changed the title transform_by and XmlAttribute Looping via xmap Jun 2, 2016
@jamesnolanverran
Copy link

jamesnolanverran commented Jun 3, 2016

Using xpath instead of xmap, and "//Query" instead of "//Query/cars" comes close to the desired output:

 request_body |> xpath(
      ~x"//Query"k,
      cars: [
          ~x"./cars"k,
          bmw: [
            ~x"./bmw"lk,
            specs: [
              ~x"./specs"k,
                model: ~x"./model/text()"s,
                engine: ~x"./engin/text()"s
          ]
        ]
      ]
    )

Output:

[cars: 
   [bmw: 
     [
       [specs: [model: "5 seriesw", engine: ""]],
       [specs: [model: "3 seriesw", engine: ""]]
     ]
   ]
]

@programisti
Copy link
Author

@jamesnolanverran thanks I see its close to this but I need this ouput somehow

[cars: 
   [bmw: 
     [
       [specs: [model: "5 seriesw", engine: ""]]
     ],
   [bmw: 
     [
       [specs: [model: "3 seriesw", engine: ""]]
     ]
   ]
]

logically this code should generate, but it does not

request_body |> xpath(
      ~x"//Query"k,
      cars: [
          ~x"./cars"lk,
          bmw: [
            ~x"./bmw"k,
            specs: [
              ~x"./specs"k,
                model: ~x"./model/text()"s,
                engine: ~x"./engin/text()"s
          ]
        ]
      ]
    )

@xurde
Copy link

xurde commented Jun 3, 2016

Actually we have experienced the same issue while addressing lists using the format ~x"//some/path"l.
I've checked code in the library but it seems quite a tricky part. Any chance to be fixed?

Thanks!

@jamesnolanverran
Copy link

jamesnolanverran commented Jun 3, 2016

*Edited - here's one I came up with. A little long winded though...
*Edited again to get rid of duplicated code

def run do
  base_node = request_body |> xpath(~x"//Query"l)
  paths = ["cars", "bmw", "specs"]
  process_node(base_node, paths)
end
def process_node(outer_node, [ path | tail ]) do
  outer_node
  |> Enum.map(fn (node) ->
    inner_node = node |> xpath(~x"./#{path}"l)
    {
      node |> xpath(~x"name(.)"s) |> String.to_atom,
      process_node(inner_node, tail)
    }
  end)
end
def process_node(outer_node, []) do
  outer_node
  |> Enum.map(fn (node) ->
    {
      node |> xpath(~x"name(.)"s) |> String.to_atom,
      outer_node |> spec_details |> List.flatten
    }
  end)
end

def spec_details(node) do
  node
  |> Enum.map(fn (spec_node) ->
    [
      model: spec_node |> xpath(~x"./model/text()"s),
      engine: spec_node |> xpath(~x"./engine/text()"s)
    ]
  end)
end


# OUTPUT:

[Query: [cars: [bmw: [specs: [model: "5 seriesw", engine: "4.4"]],
   bmw: [specs: [model: "3 seriesw", engine: "3.0"]]]]]

@jamesnolanverran
Copy link

Still playing with this a bit - I wrote a test that fails.

test "read me examples", %{simple: simple, readme: readme} do
# ....
  result = readme |> xmap(
      matchups: [
        ~x"//game/matchups/matchup"lk,
        teams: [
          ~x"./teams"lk,
          team: [
            ~x"./team"lk,
            name: ~x"./name/text()"s,
            id: ~x"./id/text()"s
          ]
        ]
      ]
  )
  assert result == %{
    matchups: [
      [teams: [
        [team: [name: "Team One", id: "1"]],
        [team: [name: "Team Two", id: "2"]]
        ]
      ],
      [teams: [
        [team: [name: "Team Two", id: "2"]],
        [team: [name: "Team Three", id: "3"]]
        ]
      ],
      [teams: [
        [team: [name: "Team One", id: "1"]],
        [team: [name: "Team Three", id: "3"]]
        ]
      ]
    ]
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants