Wanting to work with an XML file from the Powershell command "Get-GPOReport -All -Domain $domain -ReportType XML -Path C:\GPOReportsAll.xml", I quickly realized that it would be quite difficult with this file format and the XML library of Purebasic.
I therefore looked for a way to convert this XML file to Json. I couldn't find an algorithm in Purebasic and after a few hours of searching on the web, I found one in Javascript.
From there, I tried to include this script in a WebViewGadget and here's the result:
Code: Select all
Enumeration Window
#mainForm
EndEnumeration
Enumeration Gadget
#HideWeb
EndEnumeration
Global HTML.s
Procedure.s HtmlCode()
HTML = ~"<input type=\"file\" id=\"file-input\" />" + #CRLF$ +
; ~"<button id=\"btnCopy\">Copy to clipboard</button>"+ #CRLF$ +
~"<h3>Contents of the xml file :</h3>" + #CRLF$ +
~"<pre id=\"file-content\"></pre>"
SetGadgetItemText(#HideWeb, #PB_Web_HtmlCode , HTML)
EndProcedure
Procedure PushJSScript()
Protected script$ = PeekS(?JSFile, ?JSFileEnd - ?JSFile, #PB_UTF8 | #PB_ByteLength)
WebViewExecuteScript(#HideWeb, script$)
EndProcedure
OpenWindow(#mainForm, 88, 244, 1000, 600, "Xml2Json", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
WebViewGadget(#HideWeb, 0, 0, 1000, 600, #PB_WebView_Debug)
HtmlCode()
PushJSScript()
Repeat
event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow
DataSection
JSFile:
IncludeBinary "xmltojson.js"
JSFileEnd:
EndDataSection
Code: Select all
var globaljsonString = '';
document.getElementById('file-input')
.addEventListener('change', readSingleFile, false);
// https://stackoverflow.com/questions/3582671/how-to-open-a-local-disk-file-with-javascript
function readSingleFile(e) {
var file = e.target.files[0];
if (!file) {return;}
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
displayContents(contents);
// convert Xml data to Json data
const parser = new DOMParser();
const srcDOM = parser.parseFromString(contents, "application/xml");
var jsonObject = xml2json(srcDOM);
// transform object into string
var jsonString = JSON.stringify(jsonObject, null, 2);
globaljsonString = jsonString; // for the copy to clipboard function
// starting a download file operation of our json data
DownloadJsonData(jsonString);
};
reader.readAsText(file);
}
function displayContents(contents) {
var element = document.getElementById('file-content');
element.textContent = contents;
return element.textContent;
}
// convert Xml data to Json
// https://dev.to/niinpatel/converting-xml-to-json-using-recursion-2k4j
function xml2json(srcDOM) {
let children = [...srcDOM.children];
if (!children.length) {
if (srcDOM.hasAttributes()) {
var attrs = srcDOM.attributes;
var output = {};
for(var i = attrs.length - 1; i >= 0; i--) {
output[attrs[i].name] = attrs[i].value;
}
output.value = srcDOM.innerHTML;
return output;
} else {
return srcDOM.innerHTML;
}
}
let jsonResult = {};
for (let child of children) {
let childIsArray = children.filter(eachChild => eachChild.nodeName === child.nodeName).length > 1;
if (childIsArray) {
if (jsonResult[child.nodeName] === undefined) {
jsonResult[child.nodeName] = [xml2json(child)];
} else {
jsonResult[child.nodeName].push(xml2json(child));
}
} else {
jsonResult[child.nodeName] = xml2json(child);
}
}
return jsonResult;
}
// save the json file in download directory
function DownloadJsonData(jsonData) {
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([jsonData], {type: 'text/plain'}));
a.setAttribute('download', 'data.json');
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
// copy to clipboard
/* var btn = document.getElementById('btnCopy');
var clipboard =
{
data : '',
intercept : false,
hook : function (evt)
{
if (clipboard.intercept)
{
evt.preventDefault();
evt.clipboardData.setData('text/plain', clipboard.data);
clipboard.intercept = false;
clipboard.data = '';
}
}
};
window.addEventListener('copy', clipboard.hook);
btn.addEventListener('click', onButtonClick);
function onButtonClick()
{
clipboard.data = globaljsonString;
if (window.clipboardData)
{
window.clipboardData.setData('Text', clipboard.data);
}
else
{
clipboard.intercept = true;
document.execCommand('copy');
}
} */
Here is another version of the JavaScript that better manages namespaces :
Code: Select all
//var globaljsonString = '';
document.getElementById('file-input');
document.addEventListener('change', readSingleFile, false);
// https://stackoverflow.com/questions/3582671/how-to-open-a-local-disk-file-with-javascript
function readSingleFile(e) {
var file = e.target.files[0];
if (!file) {return;}
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
displayContents(contents);
// convert Xml data to Json data
const parser = new DOMParser();
const srcDOM = parser.parseFromString(contents, "application/xml");
var jsonObject = xml2json(srcDOM);
// transform object into string
var jsonString = JSON.stringify(jsonObject, null, 2);
// globaljsonString = jsonString; // for the copy to clipboard function
// starting a download file operation of our json data
DownloadJsonData(jsonString);
};
reader.readAsText(file);
}
function displayContents(contents) {
var element = document.getElementById('file-content');
element.textContent = contents;
console.log(element.textContent);
return element.textContent;
}
// convert Xml data to Json
function xml2json(srcDOM) {
// Crée un objet JSON
let obj = {};
// Si l'élément a des attributs, les ajouter à l'objet
if (srcDOM.attributes) {
for (let i = 0; i < srcDOM.attributes.length; i++) {
const attr = srcDOM.attributes[i];
obj[attr.nodeName] = attr.nodeValue;
}
}
// Si l'élément a des enfants
if (srcDOM.hasChildNodes()) {
for (let i = 0; i < srcDOM.childNodes.length; i++) {
const item = srcDOM.childNodes[i];
const nodeName = item.nodeName;
// Gérer les espaces de noms
const localName = nodeName.split(':').pop(); // Récupérer le nom local sans le préfixe
// Si c'est un élément texte
if (item.nodeType === 3) {
const textContent = item.nodeValue.trim();
if (textContent) {
obj['#text'] = textContent;
}
} else {
// Appel récursif pour les éléments enfants
const childJson = xml2json(item);
if (obj[localName]) {
// Si l'élément existe déjà, le convertir en tableau
if (!Array.isArray(obj[localName])) {
obj[localName] = [obj[localName]];
}
obj[localName].push(childJson);
} else {
obj[localName] = childJson;
}
}
}
}
// Simplifier les valeurs
for (const key in obj) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
// Si l'objet a un seul enfant qui est un texte, le convertir en valeur simple
if (Object.keys(obj[key]).length === 1 && obj[key]['#text']) {
obj[key] = obj[key]['#text'];
} else if (Array.isArray(obj[key]) && obj[key].length === 1) {
// Si c'est un tableau avec un seul élément, le convertir en objet
obj[key] = obj[key][0];
}
}
}
return obj;
}
// save the json file in download directory
function DownloadJsonData(jsonData) {
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([jsonData], {type: 'text/plain'}));
a.setAttribute('download', 'data.json');
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
// copy to clipboard
/* var btn = document.getElementById('btnCopy');
var clipboard =
{
data : '',
intercept : false,
hook : function (evt)
{
if (clipboard.intercept)
{
evt.preventDefault();
evt.clipboardData.setData('text/plain', clipboard.data);
clipboard.intercept = false;
clipboard.data = '';
}
}
};
window.addEventListener('copy', clipboard.hook);
btn.addEventListener('click', onButtonClick);
function onButtonClick()
{
clipboard.data = globaljsonString;
if (window.clipboardData)
{
window.clipboardData.setData('Text', clipboard.data);
}
else
{
clipboard.intercept = true;
document.execCommand('copy');
}
} */
I save the result of the conversion in a file "data.json" but you can also copy the result to the clipboard by uncommenting the last paragraph of the javascript and the corresponding line for the "btnCopy" button in the Purebasic code.
Don't hesitate to share your comments to correct and improve this code. (I'm a beginner in Javascript and web interface)