Powered by AppSignal & Oban Pro

XML extractor App

idex_de_xml_parser_Release_0.1.0.livemd

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])