I'm currently searching for a way to create a JSON file (versions.json) with a key and a value from an object within JavaScript. To create the JSON file, I've this object here:
["V1_config-interfaces.json","V2_config-interfaces.json","V3_config-interfaces.json","versions.json"]
I need to loop now some way over this object and check if the current file is not the versions.json because this is the created file.
The JSON file must looks like this:
{
"V1": "V1_config-interfaces.json",
"V2": "V2_config-interfaces.json",
"V3": "V3_config-interfaces.json"
}
So the key is always the version number before the underscore. What I've tried is this here:
const fs = require('fs');
const interfaces = fs.readdirSync('./src/interfaces/');
fs.writeFile('./src/interfaces/versions.json', JSON.stringify(interfaces), (err) => {
if (err) throw err;
console.log('versions.js successfully created');
});
But this generates the same result like the object looks like. So how can I reach my goals?
Use Array#reduce and regex. This strips the file version and adds it as a key to your object and ignores anything that doesn't have a version number. It also checks if the version has _ character following immediately after.
const data = ["V1_config-interfaces.json","V2_config-interfaces.json","V3_config-interfaces.json","versions.json", "V4shouldntwork.json", "shouldntwork_V5_.json", "V123_shouldwork.json"];
const res = data.reduce((a,v)=>{
const version = v.match(/^V[1-9]+(?=_)/);
if(version === null) return a;
a[version.shift()] = v;
return a;
}, {});
console.log(res);
Related
I have a javascript file that has an object I'd like to be read by Python (Python 3 is just fine). Something like this:
let variable_i_do_not_want = 'foo'
let function_i_do_not_wnt = function() {
}
// .. etc ..
// --- begin object I want ---
myObject = {
var1: 'value-1',
var2: 'value-2',
fn2: function() {
"I don't need functions.."
},
mySubObject: {
var3: 'value-3',
.. etc ..
}
}
// --- end object I want ---
// .. more stuff I don't want ..
I want to convert myObject to a python dict object. Note I don't really need the functions, just keys and values.
I'm fine with (and capable) adding comment markers before/after and isolating the object. But I think I need a library to convert that string into a Python dict. Is this possible?
Doing this using python would be a lot of work that can be avoided if you could add a few things directly in your javascript file. (as you told you could modify the js file)
I assume that you have nodejs and npm preinstalled (if not then you can install it from here
You need to add these lines of code at the end of the JS file.
const fs = require("fs");
const getVals = (obj) => {
let myData = {};
for (const key in obj) {
if (
!(typeof obj[key] === "function") && // ignore functions
(!(typeof obj[key] == "object") || Array.isArray(obj[key])) // ignore objects (except arrays)
) {
myData[key] = obj[key];
} else if (typeof obj[key] === "object") { // if it's an object, recurse
myData = {
...myData,
...getVals(obj[key]),
};
}
}
return myData;
};
// storing the data into a json file
fs.writeFile(
"myjsonfile.json",
JSON.stringify(JSON.stringify(getVals(myObject))), //change your variable name here instead of myObject (if needed)
(err) => {
if (err) throw err;
console.log("complete");
}
);
once you add this you can run the js file by
~$ npm init -y
~$ node yourjsfile.js
This will make a new file named myjsonfile.json with the data which you can load from python like this
import json
with open('myjsonfile.json') as file:
d=json.loads(file.read()) #your dict
print(d)
;)
I can't believe that I'm asking an obvious question, but I still get the wrong in console log.
Console shows crawl like "[]" in the site, but I've checked at least 10 times for typos. Anyways, here's the javascript code.
I want to crawl in the site.
This is the kangnam.js file :
const axios = require('axios');
const cheerio = require('cheerio');
const log = console.log;
const getHTML = async () => {
try {
return await axios.get('https://web.kangnam.ac.kr', {
headers: {
Accept: 'text/html'
}
});
} catch (error) {
console.log(error);
}
};
getHTML()
.then(html => {
let ulList = [];
const $ = cheerio.load(html.data);
const $allNotices = $("ul.tab_listl div.list_txt");
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : $(this).find("list_txt title").text(),
url : $(this).find("list_txt a").attr('href')
};
});
const data = ulList.filter(n => n.title);
return data;
}). then(res => log(res));
I've checked and revised at least 10 times
Yet, Js still throws this result :
root#goorm:/workspace/web_platform_test/myapp/kangnamCrawling(master)# node kangnam.js
[]
Mate, I think the issue is you're parsing it incorrectly.
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : $(this).find("list_txt title").text(),
url : $(this).find("list_txt a").attr('href')
};
});
The data that you're trying to parse for is located within the first index of the $(this) array, which is really just storing a DOM Node. As to why the DOM stores Nodes this way, it's most likely due to efficiency and effectiveness. But all the data that you're looking for is contained within this Node object. However, the find() is superficial and only checks the indexes of an array for the conditions you supplied, which is a string search. The $(this) array only contains a Node, not a string, so when you you call .find() for a string, it will always return undefined.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
You need to first access the initial index and do property accessors on the Node. You also don't need to use $(this) since you're already given the same exact data with the element parameter. It's also more efficient to just use element since you've already been given the data you need to work with.
$allNotices.each(function(idx, element) {
ulList[idx] = {
title : element.children[0].attribs.title,
url : element.children[0].attribs.href
};
});
This should now populate your data array correctly. You should always analyze the data structures you're parsing for since that's the only way you can correctly parse them.
Anyways, I hope I solved your problem!
I am using node.js, and i want to add the arguments from a command and the server id as a key:value pair into a json file like this:
{
"guildid": "args",
"guildid2": "args2",
}
And the current code that i have is far from what i want, where this code:
const command = args.shift().toLowerCase();
const args = message.content.slice(config.prefix.length).trim().split(' ');
if (command === 'setup') {
const guildid = message.guild.id
const data = {
[guildid]: `${args}`
}
const groupname = JSON.stringify(data, null, 2);
fs.writeFile('./groups.json', groupname,{flags: "a"}, finished);
function finished(err) {
message.channel.send(`Success! Your group, **${args}**, has been registered to **${message.guild.name}**`
)}
Outputs what i want to the json file, but if i run the command again it just appends to the end:
{
"guildid": "args"
}{
"guildid2": "args2"
}
I understand now that using the a flag just appends to the end no matter what and const data is what is giving it the brackets, but i want to know how to be able to format it in the way i showed at the beginning. Apologies for any glaring errors i have made, this is one of my first times using javascript and node.js.
You'll have to get the original file first using fs.readFile[Sync] and JSON.parse, and then add on the property as you would any other object:
obj.key = 'value';
// or in your case:
obj[key_variable] = 'value';
You should also omit the 'a' flag as it will append another object (resulting in a syntax error) instead of modifying the one already there. Your code should look like this:
const guildid = message.guild.id;
const data = JSON.parse(fs.readFileSync('/groups.json'));
/*
You could either use:
data[guildid] = `${args}`;
OR, when stringifying to the file:
const groupname = JSON.stringify({
...data,
[guildid]: `${args}`
}, null, 2);
Either way will work
*/
data[guildid] = `${args}`;
const groupname = JSON.stringify(data, null, 2);
// remove { flags: 'a' }
fs.writeFile('./groups.json', groupname, finished);
// you should probably write some error handling
function finished(err) {
message.channel.send(
`Success! Your group, **${args}**, has been registered to **${message.guild.name}**`
);
}
I've a image input in my webpage and input's output (File object) is saved inside the Question class. questionArr is a array of Question objects
let questionsArr = []; // Array of Question
class Question {
constructor(id) {
this.id = id;
this.image = false;
}
}
when the input value of image input changes, following function calls.
const handleImages = evt => {
let id = evt.target.id; // quizCoverImg or a integer (0,1,...)
const file = evt.target.files[0];
if (file && file.type.startsWith("image/")) {
if (id == "quizCoverImg") {
coverImage = file; // declared in top of the code
// console.log(coverImage) => File {name: "cat.png", lastModified ...}
// Returns a file object, which is correct
} else {
questionsArr[id].image = file;
// console.log(questionsArr[id].image) => File {name: "cat.png", lastModified ...}
// Returns a file object, which is correct
}
}
};
To this point everything works fine. Problem arise when I use above variables somewhere eles
const somewhereElse = () => {
console.log(coverImage); // File {name: "cat.png", lastModified ...} ✔
console.log(typeof coverImage); // object ✔
console.log(questionsArr[0].image); // C:\fakepath\cat.jpg ❓ should return a file object as mentioned above
console.log(typeof questionsArr[0].image); // string ❓
}
I know FileReader() exist, but I want to figure out why I'm getting two different outputs here.
Issue occurred in svelte#3.22.2
Edit 1: Places where questionArr used
This add Question to array
const addQuestion = () => {
const q = new Question(n);
questionsArr = [...questionsArr, q]; // because I'm using svelte :)
n++;
};
Then used in above handleImage()
The key difference is in the toString() method that affects what you are looking at. There is not much context to help debug the details of exactly how you are running this and how you are inspecting the values.
When you have selected a file in a form file input, the browser converts the path to a "fakepath" so that while the script can access the selected file, it cannot learn about the user's directory structure. The filename/path is a reasonable default toString result when trying to inspect/print the file object.
i need to make Array for data grid.
Input is XML(string). With lots of unnecessary data, i need only array "a:Client"
Here is my code which works, but I think it's not too clean to set a way like this.
parse(XML){
var parseString = require('react-native-xml2js').parseString;
var xml = XML;
parseString(xml, (err, result) => {
this.setState({rows: result["s:Envelope"]["s:Body"][0].GetClientsResponse[0].GetClientsResult[0]["a:Client"]});
});
}
Here is XML String
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetClientsResponse xmlns="http://tempuri.org/"><GetClientsResult xmlns:a="http://schemas.datacontract.org/2004/07/tt4t.Dispatching.ApplicationServer.Data.CommonData" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><a:Client><a:ClientID>0</a:ClientID><a:Name/></a:Client><a:Client><a:ClientID>12</a:ClientID><a:Name>Magistrát města Liberec</a:Name></a:Client><a:Client><a:ClientID>30</a:ClientID><a:Name>Krajský úřad Libereckého kraje</a:Name></a:Client><a:Client><a:ClientID>31</a:ClientID><a:Name>OC Nisa</a:Name></a:Client><a:Client><a:ClientID>32</a:ClientID><a:Name>Globus</a:Name></a:Client><a:Client><a:ClientID>33</a:ClientID><a:Name>Die Länderbahn GmbH DLB</a:Name></a:Client><a:Client><a:ClientID>34</a:ClientID><a:Name>Magistrát města Jablonec nad Nisou</a:Name></a:Client><a:Client><a:ClientID>35</a:ClientID><a:Name>Dopravní podnik měst Liberce a Jablonce n.N.</a:Name></a:Client><a:Client><a:ClientID>36</a:ClientID><a:Name>Liplastec</a:Name></a:Client><a:Client><a:ClientID>37</a:ClientID><a:Name>CBRE Česká republika</a:Name></a:Client><a:Client><a:ClientID>38</a:ClientID><a:Name>Cinestar</a:Name></a:Client><a:Client><a:ClientID>39</a:ClientID><a:Name>České dráhy a.s.</a:Name></a:Client><a:Client><a:ClientID>40</a:ClientID><a:Name>DENSO MANUFACTURING CZECH s.r.o.</a:Name></a:Client><a:Client><a:ClientID>41</a:ClientID><a:Name>Hasiči</a:Name></a:Client><a:Client><a:ClientID>42</a:ClientID><a:Name>MŠ Lísteček ((N.Ruda)</a:Name></a:Client><a:Client><a:ClientID>43</a:ClientID><a:Name>MŠ Tanvaldská (vč. pobočky Poštovní)</a:Name></a:Client><a:Client><a:ClientID>44</a:ClientID><a:Name>Policie ČR</a:Name></a:Client><a:Client><a:ClientID>45</a:ClientID><a:Name>SOŠ Kateřinky</a:Name></a:Client><a:Client><a:ClientID>46</a:ClientID><a:Name>Sportkids</a:Name></a:Client><a:Client><a:ClientID>47</a:ClientID><a:Name>SŽDC, s.o.</a:Name></a:Client><a:Client><a:ClientID>48</a:ClientID><a:Name>Záchranná služba</a:Name></a:Client><a:Client><a:ClientID>49</a:ClientID><a:Name>ZŠ Nad Školou</a:Name></a:Client><a:Client><a:ClientID>50</a:ClientID><a:Name>SKI KLUB Jizerska 50</a:Name></a:Client><a:Client><a:ClientID>51</a:ClientID><a:Name>TJ Dukla Liberec, z.s.</a:Name></a:Client><a:Client><a:ClientID>52</a:ClientID><a:Name>Jiný, viz poznámka</a:Name></a:Client><a:Client><a:ClientID>53</a:ClientID><a:Name>KORID LK, spol. s r.o.</a:Name></a:Client><a:Client><a:ClientID>54</a:ClientID><a:Name>STUDENT AGENCY k.s.</a:Name></a:Client><a:Client><a:ClientID>55</a:ClientID><a:Name>Boveraclub z.s.</a:Name></a:Client><a:Client><a:ClientID>56</a:ClientID><a:Name>Archa 13</a:Name></a:Client><a:Client><a:ClientID>57</a:ClientID><a:Name>Pekárny</a:Name></a:Client><a:Client><a:ClientID>58</a:ClientID><a:Name>MŠ Sídliště - Skloněná</a:Name></a:Client><a:Client><a:ClientID>59</a:ClientID><a:Name>Vratislavice</a:Name></a:Client><a:Client><a:ClientID>60</a:ClientID><a:Name>První festivalová s.r.o.</a:Name></a:Client><a:Client><a:ClientID>61</a:ClientID><a:Name>Městský obvod Liberec - Vratislavice nad Nisou</a:Name></a:Client><a:Client><a:ClientID>62</a:ClientID><a:Name>Preciosa</a:Name></a:Client><a:Client><a:ClientID>63</a:ClientID><a:Name>Central Europe Spartan Race ESR Enterprises Czech</a:Name></a:Client><a:Client><a:ClientID>64</a:ClientID><a:Name>Kümpers Textil, s.r.o.</a:Name></a:Client><a:Client><a:ClientID>65</a:ClientID><a:Name>Základní škola a Mateřská škola, Stráž n.N.</a:Name></a:Client><a:Client><a:ClientID>66</a:ClientID><a:Name>Základní škola a mateřská škola logopedická, LBC</a:Name></a:Client><a:Client><a:ClientID>165</a:ClientID><a:Name>Zájezd stř. 704</a:Name></a:Client><a:Client><a:ClientID>166</a:ClientID><a:Name>DPMLJ X11</a:Name></a:Client><a:Client><a:ClientID>167</a:ClientID><a:Name>DPMLJ 2 a 3</a:Name></a:Client><a:Client><a:ClientID>168</a:ClientID><a:Name>DPMLJ 5 a 11</a:Name></a:Client></GetClientsResult></GetClientsResponse></s:Body></s:Envelope>
Your code works, but I think that it have two things that can be done better....
1) It's not readable, if you'll read this code in a year it'll be difficult to understand what you are looking for, so I would wrap that:
{rows: result["s:Envelope"]["s:Body"][0].GetClientsResponse[0].GetClientsResult[0]["a:Client"]}
in a function like:
getClient(result)
2) It's not reusable, if the XML change or you need to find some other data it'll break, so try to use a function with a parameter that finds exactly what you need recursively if necessary
(You can give a look here, I know that you have array, but you can search recursively also for your arrays)
The only thing I worry about the above code is that it missed error checking. I am sure how confident that you are about your API and the schema will behave as expected. I feel it is good to have error checking when you are accessing a nested property of a nested object.
afterParsing(err, result){
if(err){
// Handle error
return [];
}
try {
const res = result["s:Envelope"]["s:Body"][0].GetClientsResponse[0].GetClientsResult[0]["a:Client"];
return res;
} catch (error) {
return [];
}
}
parse(XML){
var parseString = require('react-native-xml2js').parseString;
var xml = XML;
parseString(xml, (err, result) => {
this.setState({rows: this.afterParsing(err, result)});// if afterParsing and this function are in the class
});
}
If this piece of code is going to be run in the browser you can also try DOMParser.
const stringContainingXMLSource = `<your xml string>`;
var parser = new DOMParser();
var doc = parser.parseFromString(stringContainingXMLSource, "application/xml");
console.log(Array.from(doc.querySelectorAll('Envelope > Body > GetClientsResponse > GetClientsResult > Client')).map(n => n.textContent));