Цель приведенного ниже кода — извлечь данные из 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, либо данные не возвращаются. Как это решить?
К сожалению, я думаю, что вы показываете 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);
}
<entries name = "system">
и <entries name = "memory">
. И полученные значения помещаются в электронную таблицу с помощью setValues
.<entries name = "memory_bank">
из <entries name = "memory">
. Пожалуйста, будьте осторожны с этим.В этом ответе предполагается, что ваши файлы данных XML имеют одинаковую структуру. Если в файлы включены XML-данные различных структур, этот измененный сценарий может быть невозможен. Пожалуйста, будьте осторожны с этим.
Если отображаемый XML-код отличается от фактического и предложенная мной модификация не может быть использована, можете ли вы предоставить действительные данные XML? По этому я хотел бы его изменить.
Вы правильно угадали! Это первый элемент <entries name = "memory Bank">. Но если бы это было второе, какое изменение кода потребовалось бы?
@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]);
. При этом используется второй элемент.
Все еще рассчитывая на вашу доброту, "memory_bank" приносит данные случайным образом. Существуют XML, которые могут иметь до четырех элементов «memory_bank». Существует ли автоматический способ поиска информации, в которой атрибут «тип» не равен «Пустой слот»?
@Lucas Góes Спасибо за ответ. Я рад, что ваш второй вопрос был решен. Что касается вашего третьего вопроса, я должен извиниться за плохое знание английского языка. К сожалению, я не могу понять ваш третий вопрос. Я глубоко извиняюсь, что не смогу в ближайшее время ответить на ваши различные вопросы. Но мне бы хотелось вас поддержать. Итак, можете ли вы опубликовать свой третий вопрос как новый вопрос, включив дополнительную информацию? Если вы можете помочь решить ваш третий вопрос, я буду рад. Можете ли вы сотрудничать, чтобы сделать это?
При воспроизведении вашей проблемы скрипт выдает ошибку
"Error on line 108: The element type "entries" must be terminated by the matching end-tag "</entries>"
, что означает, что структура вашего XML нарушена. Можете ли вы дважды проверить имеющиеся у вас образцы XML-данных, чтобы мы могли точно воспроизвести вашу проблему?