XML extractor App
Mix.install(
[
{:kino, "~> 0.17.0"},
{:sweet_xml, "~> 0.7.5"},
{:elixir_mbcs, github: "woxtu/elixir-mbcs", tag: "0.1.3"},
{:codepagex, "~> 0.1.6"}
],
config: [
codepagex: [
encodings: [
"VENDORS/MICSFT/WINDOWS/CP1252"
]
]
]
)
Section
XML Diagnostics report extractor
This app will extract the diagnostics related information from the XML files generated from the IDEX tool.
defmodule FileHandler do
def get() do
Kino.Input.file("Upload your file", accept: ~w(.xml))
end
def run(file_ref) do
# 1. Read the raw binary
path = Kino.Input.file_path(file_ref)
content = File.read!(path)
# 2. Convert from Windows-1252 to UTF-8
# Codepage 1252 is specifically for Western European languages (German)
case Codepagex.to_string(content, "VENDORS/MICSFT/WINDOWS/CP1252") do
{:ok, utf8_string} ->
# 3. Fix the XML header so parsers don't get confused
final_xml = String.replace(utf8_string, "Windows-1252", "UTF-8", global: false)
%{path: path, content: final_xml}
{:error, reason} ->
Mix.shell().error("Conversion failed: #{inspect(reason)}")
end
end
end
defmodule Ecu do
@enforce_keys [:id]
defstruct id: "",
swv: ""
end
defmodule User do
defstruct name: "",
client: "",
file: "",
time: "",
date: ""
def to_string(user) do
"""
### File:
#{user.file}
| User | PC Name| date| time|
| :---: | :---:| :---:| :---: |
| #{user.name} | #{user.client}| #{user.date} | #{user.time}|
"""
end
end
defmodule VehicleData do
defstruct km: 0,
vin: "",
name: ""
def to_string(vehicle) do
"""
| Name | VIN| Km|
| :---: | :---:| :---:|
| #{vehicle.name} | #{vehicle.vin}| #{vehicle.km} |
"""
end
end
defmodule DiagnosticsData do
defstruct id: "", description: "", sw: "", coding: ""
def to_string(diagnostics) do
"""
| ID | SW | Description | Coding |
| :---: | :---:| :---:| :---:|
| #{diagnostics.id} | #{diagnostics.sw}| #{diagnostics.description} | #{diagnostics.coding}|
"""
end
end
defmodule XmlHandler do
import SweetXml
def getUser(content) do
%User{
name: content |> xpath(~x"//User/text()"S),
client: content |> xpath(~x"//ClientName/text()"S),
file: content |> xpath(~x"//Dateiname/text()"S),
time: content |> xpath(~x"//Zeit/text()"),
date: content |> xpath(~x"//Datum/text()")
}
end
def getVehicleData(content) do
%VehicleData{
vin: content |> xpath(~x"//Fahrgestellnummer/text()"S),
km: content |> xpath(~x"//WegStrecke/text()"i),
name: content |> xpath(~x"//UserProjekt/text()"S)
}
end
def getDiagnosticsData(%{id: id, sw: sw, description: description, coding: coding}) do
%DiagnosticsData{id: id, sw: sw, description: description, coding: coding}
end
def getEcus(content) do
diagnostics =
content
|> xmap(
Diagnosebloecke: [
~x"//Diagnosebloecke/Diagnoseblock"l,
description: ~x"./Systembezeichnung/text()"S,
coding: ~x"./Codierung/text()"S,
sw: ~x"./SWVersion/text()"S,
id: ~x"./Adresse/text()"S
]
)
Map.get(diagnostics, :Diagnosebloecke)
|> Enum.map(&getDiagnosticsData/1)
end
def getEcus(content, ids) do
diagList = getEcus(content)
ids
|> Enum.map(fn id -> diagList |> Enum.filter(fn map -> map.id == id end) end)
|> List.flatten()
end
end
form =
Kino.Control.form(
[
file: FileHandler.get()
],
submit: "Parse"
)
outputFrame = Kino.Frame.new()
h1 =
Kino.HTML.new("""
Diagnostics Data extractor
This app helps you decode and extract the specific fields of the Idex XML file.
""")
Kino.listen(form, fn event ->
%{data: %{file: %{file_ref: file_ref}}} = event
Kino.Frame.render(outputFrame, "Parsing XML...")
{:file, validator} = file_ref
if validator == "" do
Kino.interrupt!(:error, "Please provide the XML file..")
end
v = FileHandler.run(file_ref)
userDetails =
v.content
|> XmlHandler.getUser()
|> User.to_string()
|> Kino.Markdown.new()
vehicleDetails =
v.content
|> XmlHandler.getVehicleData()
|> VehicleData.to_string()
|> Kino.Markdown.new()
ecuDetails =
v.content |>
#XmlHandler.getEcus( ["8103"])
XmlHandler.getEcus(["0009", "0019", "8103", "8124", "812C"])
tabs =
Kino.Layout.tabs(
User: userDetails,
Vehicle: vehicleDetails,
Important_IDs:
Kino.DataTable.new(
ecuDetails
),
All_IDs: Kino.DataTable.new(XmlHandler.getEcus(v.content)),
Raw: v.content
)
Kino.Frame.render(outputFrame, tabs)
end)
Kino.Layout.grid([h1, form, outputFrame])