Cara mengekstrak data dan data atribut dari XMLElement

Sep 22 2020

Saya mencoba menulis fungsi untuk mengekstrak data dan data atribut dari XMLElement dengan cara yang sama. Saya telah mengikuti contoh dari tutorial Transformasi XML Mathematica dan solusi Mathematica StackExchange di sini

Ekstrak data atribut dari XMLElement

Namun, fungsi yang saya tulis mengembalikan daftar kosong. Saya yakin fungsi Kasus melintasi string XML satu kali dan, akibatnya, tidak mengurai XMLElement untuk kedua kalinya seperti yang saya kira.

MWL saya dimulai dengan membaca fleetXMLString dari file dengan Impor [fName]

    XMLObject[
  "Document"][{XMLObject["Declaration"]["Version" -> "1.0", 
   "Encoding" -> "utf-8"]}, 
 XMLElement[
  "Fleet", {}, {XMLElement[
    "SomeVehicle", {}, {XMLElement["Name", {}, {"BJ#00"}], 
     XMLElement[
      "Bus", {}, {XMLElement["Shape", {}, {"parallelepiped"}], 
       XMLElement["Length", {"unit" -> "Distance"}, {"0.5"}], 
       XMLElement["Width", {"unit" -> "Distance"}, {"0.4"}], 
       XMLElement["Height", {"unit" -> "Distance"}, {"0.3"}], 
       XMLElement["Density", {"unit" -> "Density"}, {"500.0"}]}]}], 
   XMLElement[
    "SomeVehicle", {}, {XMLElement["Name", {}, {"BJ#01"}], 
     XMLElement[
      "Bus", {}, {XMLElement["Shape", {}, {"parallelepiped"}], 
       XMLElement["Length", {"unit" -> "Distance"}, {"0.5"}], 
       XMLElement["Width", {"unit" -> "Distance"}, {"0.4"}], 
       XMLElement["Height", {"unit" -> "Distance"}, {"0.3"}], 
       XMLElement[
        "Density", {"unit" -> "Density"}, {"500.0"}]}]}]}], {}]

Kedua fungsi di bawah ini memberikan hasil yang diharapkan

BusPhysParam[xmlString_, name_, pName_] :=
 Cases[
  Cases[xmlString,
   XMLElement["SomeVehicle", _, {___,
     XMLElement["Name", _, {name}], ___}], Infinity],
  XMLElement["Bus", _, {___,
     XMLElement[pName, _, {dim_}], ___}] :> ToExpression[dim], 
  Infinity]
BusPhysParam[fleetXMLString, "BJ#00", "Width"]

{0.4}

dan

BusPhysParamUnit[xmlString_, name_, pName_] :=
 Cases[
  Cases[xmlString,
   XMLElement["SomeVehicle", _, {___,
     XMLElement["Name", _, {name}], ___}], Infinity],
  XMLElement["Bus", _, {___,
     XMLElement[pName, {___, "unit" -> unit_}, ___], ___}] :> unit, 
  Infinity]
BusPhysParamUnit[fleetXMLString, "BJ#00", "Width"]

{Distance}

Namun, fungsi ini mengembalikan daftar kosong

BusPhysParamMod[xmlString_, name_, pName_] :=
 Cases[
  Cases[xmlString,
   XMLElement["SomeVehicle", _, {___,
     XMLElement["Name", _, {name}], ___}], Infinity],
  XMLElement["Bus", _, {___,
     XMLElement[pName, _, {dim_}], ___,
     XMLElement[pName, {___, "unit" -> unit_}, ___]}] :> {ToExpression[dim], 
    unit}, Infinity]
BusPhysParamMod[fleetXMLString, "BJ#00", "Width"]

Apakah ada cara untuk mengekstrak nilai dan atribut secara bersamaan? Terima kasih! B

Jawaban

2 Jean-Pierre Sep 22 2020 at 14:17
BusPhysParamMod[xmlString_, name_, pName_] := 
 Cases[Cases[xmlString, 
   XMLElement[
    "SomeVehicle", _, {___, XMLElement["Name", _, {name}], ___}], 
   Infinity], 
  XMLElement[
    "Bus", _, {___, 
     XMLElement[
      pName, {___, "unit" -> unit_}, {dim_}], ___}] :> {ToExpression[
     dim], unit}, Infinity]
BusPhysParamMod[fleetXMLString, "BJ#00", "Width"]
2 MikeColacino Sep 22 2020 at 14:14

Saya pikir menggunakan Casesuntuk memecah XML mungkin bukan cara yang tepat untuk melakukannya. Saat bekerja dengan struktur bersarang seperti ini, pendekatan alami adalah menggunakan rekursi. Kode berikut dapat menggunakan pemolesan tetapi menyarankan cara umum untuk menangani XML. Ide dasarnya adalah Anda menemukan kepala struktur dan melepaskannya, lalu mengulangi apa yang tersisa. Mengingat banyaknya bentuk yang dapat diambil XML, ini memungkinkan Anda untuk menyesuaikan kode ke jenis XML bersarang apa pun yang diberikan kepada Anda, dan penguraiannya cukup mekanis setelah Anda memahami XML bersarang (yang sayangnya harus Anda lakukan jika ingin bekerja) dengan XML!)

trf[XMLObject["Document"][decl_, rest_, {}], bS_] := trf[rest, bS];
trf[XMLElement["Fleet", {}, fleetL_], bS_] := trf[#, bS] & /@ fleetL;
trf[XMLElement["SomeVehicle", {}, vehL_], bS_] := 
  If[vehL[[1]] == XMLElement["Name", {}, {bS}],
   trf[Rest[vehL]]];
trf[{XMLElement["Bus", {}, busAttL_]}] := busAttGL = busAttL;


 (* called with *)
 trf[fleetXMLString, "BJ#00"];
  1. Fungsi pertama menghapus header dokumen dan deklarasi.

  2. Yang kedua menarik "Armada" dan memetakan seluruh daftar kendaraan di armada, karena ada banyak kendaraan yang berpotensi.

  3. Fungsi ketiga mengeluarkan nama kendaraan tertentu yang Anda cari (katakan "BJ # 00") dengan IFpernyataan dan kemudian melanjutkan rekursi menghapus XMLElement "SomeVehicle".

  4. Langkah terakhir mengambil daftar atribut dan memasukkan daftar tersebut ke dalam daftar global untuk diproses lebih lanjut (mungkin bukan bagian yang paling elegan) tetapi menurut saya ini adalah solusi umum untuk masalah yang Anda ajukan, yang pada tingkat tinggi adalah "bagaimana dapatkah saya mengekstrak ciri-ciri kendaraan tertentu? " Ini menyisakan semua sifat bersama dalam bentuk dapat diproses pasca sesuai kebutuhan.

  5. Sepertinya ini {XMLElement["Shape", {}, {"parallelepiped"}], XMLElement["Length", {"unit" -> "Distance"}, {"0.5"}], XMLElement["Width", {"unit" -> "Distance"}, {"0.4"}], XMLElement["Height", {"unit" -> "Distance"}, {"0.3"}], XMLElement["Density", {"unit" -> "Density"}, {"500.0"}]}

  6. Dari sini Anda dapat mengekstrak atribut dengan memanipulasi daftar secara langsung, atau jika Anda lebih suka, Anda dapat menggunakan Casesseperti ini:

selectedAttr=Cases[busAttGL, XMLElement["Width", ___, ___]][[1]]

Dan kemudian Anda dapat mengambil aturan dan nilainya dan menyatukannya menggunakan Caseslagi dan aturan:

{"unit" /. First[Cases[selectedAttr, {"unit" -> "Distance"}]],selectedAttr[[3]][[1]]}

Saya mungkin akan masuk ke daftar itu sendiri:

`{selectedAttr[[2]][[1]][[2]], selectedAttr[[3]][[1]]}`

Keduanya menghasilkan {"Distance", "0.4"}yang Anda kejar. Ini membuatnya cukup mudah untuk melakukan permutasi atribut bus, dll.

Keduanya agak sederhana dan saya yakin seseorang di forum akan menyarankan cara yang lebih bersih untuk beralih dari formulir XMLElement ke apa yang Anda inginkan.