Извлечение данных из XML с помощью скрипта Google Apps в электронную таблицу Google

Цель приведенного ниже кода — извлечь данные из XML-файлов, хранящихся в каталоге Google Диска. Код возвращает значения для «systemEntries», но не для «memoryEntries».

function extrairDadosXML() {
  var pasta = DriveApp.getFolderById('pastaId'); // Insira o ID da pasta onde estão os arquivos XML
  var arquivos = pasta.getFiles();
  var planilha = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  
  // Cabeçalho da planilha
  planilha.appendRow(["Manufacturer", "Model", "Serial", "Total Memory", "Total Slots", "Free Slots", "Memory Type"]);
  
  while (arquivos.hasNext()) {
    var arquivo = arquivos.next();
    if (arquivo.getName().split('.').pop() === 'xml') {
      var xml = XmlService.parse(arquivo.getBlob().getDataAsString());
      var root = xml.getRootElement();
      
      var HardwareReport = root.getChild('report').getChild('data').getChild('hardware_report');
      
      var systemEntries = HardwareReport.getChild('entries').getChildren('entry');
      var memoryEntries = HardwareReport.getChild('entries').getChildren('entry');
      
      var manufacturer, model, serial, totalMemory, totalSlots, freeSlots, memoryType;
      
      for (var i = 0; i < systemEntries.length; i++) {
        var entry = systemEntries[i];
        if (entry.getAttribute('name').getValue() === 'manufacturer') {
          manufacturer = entry.getText();
        } else if (entry.getAttribute('name').getValue() === 'model') {
          model = entry.getText();
        } else if (entry.getAttribute('name').getValue() === 'serial') {
          serial = entry.getText();
        }
      }
      
      for (var j = 0; j < memoryEntries.length; j++) {
        var entry = memoryEntries[j];
        if (entry.getAttribute('name').getValue() === 'total_memory') {
          totalMemory = entry.getText();
        } else if (entry.getAttribute('name').getValue() === 'total_slots') {
          totalSlots = entry.getText();
        } else if (entry.getAttribute('name').getValue() === 'free_slots') {
          freeSlots = entry.getText();
        } else if (entry.getAttribute('name').getValue() === 'type') {
          memoryType = entry.getText();
        }
      }
      
      planilha.appendRow([manufacturer, model, serial, totalMemory, totalSlots, freeSlots, memoryType]);
    }
  }
}

Справочный XML-код приведен ниже:

<root>
 <report>
  <data>
   <description>
   ...
   </description>
   <erase_report>
   ...
   </erase_report>
   <hardware_report>
    <entries name = "system">
     <entry name = "manufacturer" type = "string">HP</entry>
     <entry name = "model" type = "string">HP ProBook 645 G4</entry>
     <entry name = "serial" type = "string">AB71G</entry>
     <entry name = "uuid" type = "string">d2e99-0d43-5c</entry>
     <entry name = "chassis_type" type = "string">Notebook</entry>
     <entry name = "asset_tag" type = "string">A93</entry>
     <entry name = "version" type = "string">DBXEnabled</entry>
     <entry name = "sku_number" type = "string">4C4</entry>
     <entries name = "boot_parameters">
      <entry name = "boot_parameter" type = "string">flr</entry>
      <entry name = "boot_parameter" type = "string">libata.allow_tpm=1</entry>
      <entry name = "boot_parameter" type = "string">loglevel=0</entry>
      <entry name = "boot_parameter" type = "string">memtest=00</entry>
      <entry name = "boot_parameter" type = "string">rd.udev.log-priority=3</entry>
      </entries>
    </entries>
    <entries name = "bios">
    ...
    </entries>
    <entries name = "processors">
     <entry name = "total_cores" type = "uint">4</entry>
     <entry name = "total_cpus" type = "uint">1</entry>
     <entries name = "processor">
      <entry name = "id" type = "uint">1</entry>
      <entry name = "model" type = "string">AMD Ryzen 3 PRO 2300U w/ Radeon Vega Mobile Gfx</entry>
      <entry name = "vendor" type = "string">AuthenticAMD</entry>
      <entry name = "nominal_frequency" type = "uint">2000000000</entry>
      <entry name = "max_frequency" type = "uint">3400000000</entry>
      <entry name = "cores" type = "uint">4</entry>
      <entry name = "threads" type = "uint">4</entry>
      <entry name = "hyperthreading" type = "string">false</entry>
      <entry name = "stepping" type = "uint">0</entry>
      <entry name = "voltage" type = "string">1.2 V</entry>
      <entry name = "external_clock" type = "string">100 MHz</entry>
      <entries name = "caches">
       <entries name = "cache">
        <entry name = "type" type = "string">Level 1 Cache</entry>
        <entry name = "size" type = "uint">384</entry>
       </entries>
       <entries name = "cache">
        <entry name = "type" type = "string">Level 2 Cache</entry>
        <entry name = "size" type = "uint">2048</entry>
       </entries>
       <entries name = "cache">
        <entry name = "type" type = "string">Level 3 Cache</entry>
        <entry name = "size" type = "uint">4096</entry>
       </entries>
      </entries>
     </entries>
    </entries>
    <entries name = "motherboard">
    ...
    </entries>
    <entries name = "memory">
     <entry name = "total_memory" type = "uint">8589934592</entry>
     <entry name = "accessible_memory" type = "uint">7219544064</entry>
     <entry name = "physical_memory" type = "uint">8589934592</entry>
     <entry name = "total_slots" type = "uint">2</entry>
     <entry name = "free_slots" type = "uint">1</entry>
     <entries name = "memory_bank">
      <entry name = "vendor" type = "string">SMART</entry>
      <entry name = "serial" type = "string">07D45D</entry>
      <entry name = "part_number" type = "string">SLSBG</entry>
      <entry name = "type" type = "string">DDR4</entry>
      <entry name = "type_detail" type = "string">Synchronous Unbuffered (Unregistered)</entry>
      <entry name = "form_factor" type = "string">SODIMM</entry>
      <entry name = "capacity" type = "uint">8589934592</entry>
      <entry name = "hz" type = "uint">2667000000</entry>
     </entries>
     <entries name = "memory_bank">
      <entry name = "type" type = "string">Empty slot</entry>
      <entry name = "form_factor" type = "string">Other</entry>
     </entries>
    </entries>
    <entries name = "tpm_devices">
    ...
    </entries>
    <entries name = "disks">
     <entries name = "disk">
      <entry name = "id" type = "uint">1</entry>
      <entry name = "internal_id" type = "uint">46</entry>
      <entry name = "index" type = "string">1 (1-1)</entry>
      <entry name = "model" type = "string">C56</entry>
      <entry name = "vendor" type = "string">LITEON</entry>
      <entry name = "serial" type = "string">00B</entry>
      <entry name = "wwnid" type = "string">50022ce</entry>
      <entry name = "firmware_revision" type = "string">V1</entry>
      <entry name = "blocksize" type = "uint">512</entry>
      <entry name = "interface_type" type = "string">SATA/SSD</entry>
      <entry name = "sed" type = "string">Self-encrypting drive</entry>
      <entry name = "average_write_speed" type = "uint">26463434</entry>
      <entry name = "average_read_speed" type = "uint">456558742</entry>
      <entry name = "capacity" type = "uint">256060514304</entry>
      <entry name = "sectors" type = "uint">5002</entry>
      <entry name = "remapped_sectors" type = "uint">0</entry>
      <entry name = "health" type = "string">good</entry>
   </hardware_report>
  </data>
  <user_data>
  ...
  </user_data>
 </report>
</root>

Я попробовал внести несколько изменений, но это не сработало. Либо он извлекает данные только из systemEntries, либо данные не возвращаются. Как это решить?

При воспроизведении вашей проблемы скрипт выдает ошибку "Error on line 108: The element type "entries" must be terminated by the matching end-tag "</entries>", что означает, что структура вашего XML нарушена. Можете ли вы дважды проверить имеющиеся у вас образцы XML-данных, чтобы мы могли точно воспроизвести вашу проблему?

SputnikDrunk2 07.03.2024 23:05
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

К сожалению, я думаю, что вы показываете XML-данные недействительно. Об этом уже упоминалось в комментарии SputnikDrunk2. Но, судя по вашему сценарию и The code returns values ​​for “systemEntries”, but not for “memoryEntries”., я предполагаю, что ваши фактические данные XML являются действительными данными. Итак, я предложил ответ, изменив отображаемые XML-данные.

И когда я увидел ваши XML-данные, выяснилось, что в <entries name = "memory_bank"> есть 2 <entries name = "memory">. И есть 2 «типа» <entry name = "type" type = "string">DDR4</entry> и <entry name = "type" type = "string">Empty slot</entry>. Но ваш сценарий этого не отражает. Поэтому, к сожалению, я не могу понять ваши фактические ожидаемые значения. Из этой ситуации я догадался, что вам, возможно, нужен первый элемент <entries name = "memory_bank">.

Когда ваш сценарий показа будет изменен, он станет следующим.

Модифицированный скрипт:

function extrairDadosXML() {
  var pasta = DriveApp.getFolderById('pastaId'); // Insira o ID da pasta onde estão os arquivos XML
  var arquivos = pasta.getFiles();
  var planilha = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  var header = ["Manufacturer", "Model", "Serial", "Total Memory", "Total Slots", "Free Slots", "Memory Type"];
  var values = [header];

  while (arquivos.hasNext()) {
    var arquivo = arquivos.next();
    if (arquivo.getName().split('.').pop() === 'xml') {
      var xml = XmlService.parse(arquivo.getBlob().getDataAsString());
      var root = xml.getRootElement();
      var HardwareReport = root.getChild('report').getChild('data').getChild('hardware_report');
      var entries = HardwareReport.getChildren();
      var systemObj = entries.find(e => e.getAttribute("name").getValue() == "system").getChildren().reduce((o, e) => {
        var t = e.getChildren();
        if (t.length == 0) {
          var k = e.getAttribute("name").getValue()
          o[k] = o[k] ? [...o[k], e.getText()] : [e.getText()];
        } else {
          t.forEach(f => {
            var k = f.getAttribute("name").getValue();
            o[k] = o[k] ? [...o[k], f.getText()] : [f.getText()];
          });
        }
        return o;
      }, {});
      var memoryObj = entries.find(e => e.getAttribute("name").getValue() == "memory").getChildren().reduce((o, e) => {
        var t = e.getChildren();
        if (t.length == 0) {
          var k = e.getAttribute("name").getValue()
          o[k] = o[k] ? [...o[k], e.getText()] : [e.getText()];
        } else {
          t.forEach(f => {
            var k = f.getAttribute("name").getValue();
            o[k] = o[k] ? [...o[k], f.getText()] : [f.getText()];
          });
        }
        return o;
      }, {});

      var valuesForSystem = ["manufacturer", "model", "serial"];
      var valuesForMemory = ["total_memory", "total_slots", "free_slots", "type"];
      var res = [
        ...valuesForSystem.map(e => systemObj[e] || ""),
        ...valuesForMemory.map(e => memoryObj[e] || ""),
      ];

      // 1st element is used.
      res = res.map(e => e[0]);

      values.push(res);
    }
  }
  planilha.getRange(1, 1, values.length, values[0].length).setValues(values);
}
  • При запуске этого сценария значения извлекаются из каждого XML-файла. И значения извлекаются из <entries name = "system"> и <entries name = "memory">. И полученные значения помещаются в электронную таблицу с помощью setValues.
  • В этом ответе используется 1-й <entries name = "memory_bank"> из <entries name = "memory">. Пожалуйста, будьте осторожны с этим.

Примечание:

  • В этом ответе предполагается, что ваши файлы данных XML имеют одинаковую структуру. Если в файлы включены XML-данные различных структур, этот измененный сценарий может быть невозможен. Пожалуйста, будьте осторожны с этим.

  • Если отображаемый XML-код отличается от фактического и предложенная мной модификация не может быть использована, можете ли вы предоставить действительные данные XML? По этому я хотел бы его изменить.

Вы правильно угадали! Это первый элемент <entries name = "memory Bank">. Но если бы это было второе, какое изменение кода потребовалось бы?

Lucas Góes 08.03.2024 03:50

@Lucas Góes Спасибо за ответ. Я рад, что ваша проблема была решена. Что касается вашего дополнительного вопроса But if it were the second, what code change would be necessary?, в этом случае измените res = res.map(e => e[0]); на res = res.map(e => e.length == 1 ? e[0] : e[1]);. При этом используется второй элемент.

Tanaike 08.03.2024 03:52

Все еще рассчитывая на вашу доброту, "memory_bank" приносит данные случайным образом. Существуют XML, которые могут иметь до четырех элементов «memory_bank». Существует ли автоматический способ поиска информации, в которой атрибут «тип» не равен «Пустой слот»?

Lucas Góes 08.03.2024 15:40

@Lucas Góes Спасибо за ответ. Я рад, что ваш второй вопрос был решен. Что касается вашего третьего вопроса, я должен извиниться за плохое знание английского языка. К сожалению, я не могу понять ваш третий вопрос. Я глубоко извиняюсь, что не смогу в ближайшее время ответить на ваши различные вопросы. Но мне бы хотелось вас поддержать. Итак, можете ли вы опубликовать свой третий вопрос как новый вопрос, включив дополнительную информацию? Если вы можете помочь решить ваш третий вопрос, я буду рад. Можете ли вы сотрудничать, чтобы сделать это?

Tanaike 09.03.2024 01:58

Другие вопросы по теме