Parsing xml using Node

Not quite home but before I get back to it can you clarify what you used as yourID? Is that the map file name?

yes. this is the path to the first articulation in the expression map. the articulations are stored in the obj[0] - obj[n].

actually these are the articulation names if you want the description it's a slightly other path.

this would be the path to the description:

[mapID.InstrumentMap.member[1]?.list.obj[0]?.string[1].value,

Ok, so back at my machine and I appear to be no further on. I've clearly missed something somewhere as I can't get to myExpression and end up with the error as shown in the image at the bottom...

var convert = nativeRequire('xml-js');


//now accessing an xml in a file structure

const fs = nativeRequire('fs');

const path = nativeRequire("path");
var xmlFromFile = fs.readFileSync(path.resolve(__dirname, "../BlankMap.expressionmap"));

var options = { compact: false, spaces: 1};
var result1 = convert.xml2js(localxml, options);
var result2 = convert.xml2json(localxml, options);
var result3 = convert.xml2js(xmlFromFile, { compact: false, spaces: 1 });
var result4 = convert.xml2json(xmlFromFile, { compact: false, spaces: 1 });

console.log('-----------------------------------------------------------');
console.log('Result 4 - JSON FROM XML FILE IN FILE STRUCTURE' + result4);
console.log('-----------------------------------------------------------');

var myExpression = [result4.InstrumentMap.member[1].list.obj[0].member[1].string.value]

console.log('myExpression' + myExpression )

i think you have to end the array with a semicolon:

Nope…

Back to trial and error until I can get something to work!…

const xml2json = nativeRequire('xml2json');

//now accessing an xml in a file structure

const fs = nativeRequire('fs');

const path = nativeRequire("path");
var xmlFromFile = fs.readFileSync(path.resolve(__dirname, '../NISS_Horn_II.expressionmap'));
console.log(xmlFromFile)

var options = { compact: false, spaces: 1};
// var result1 = convert.xml2js(localxml, options);
// var result2 = convert.xml2json(localxml, options);
// var result3 = convert.xml2js(xmlFromFile, { compact: false, spaces: 1 });
var result4 = JSON.parse(xml2json.toJson(xmlFromFile))

console.log('-----------------------------------------------------------');
console.log('Result 4 - JSON FROM XML FILE IN FILE STRUCTURE' +  result4);
console.log('-----------------------------------------------------------');

var myExpression = [result4.InstrumentMap.member[1].list.obj[0].member[1].string.value]

console.log('myExpression' + myExpression )

AWWWWWSOME

btw i used xml2json

what happens if you take an existing map?

In the code you pasted, result4 is generated with the xml2json function which I guess returns a string and not an object, hence the error when attempting to access its properties like it's an object. I suppose the xml2js function is the one you should use here.

Note: be careful, you guys are using different libraries (xml-js vs xml2json) that are likely to produce different results.

1 Like

from stackoverflow:

Also be aware that xml2json and xml-js produce a bit different JSON. When I replaced xml2json with xml-js I had to add "._attributes" everywhere where values were in attributes.

Yes I figured that might be the problem, or at least something to with the conversion like this.

So today need to align electron version to avoid the previous error and then start using xml2json and then I will be progressed to this point...

1 Like

this sounds promising.

making progress.

i can get the files:

but maps and articulations stay empty. i'm not sure about the xml2json part. i tried to convert all in one go.

here's the code:

const fs = nativeRequire('fs');
const xml2json = nativeRequire('xml2json');
const path = nativeRequire('path');

dir = path.join(__dirname, '/../../Steinberg/Cubase/Expression Maps/Native Instruments/Symphony Series');

const maps = {}
const articulations = {}


// load expression maps
fs.readdir(dir, (err, files) => {
    if (err) {throw err}
    files.forEach(file => {
        if (path.extname(file) === 'expressionmap') {
            maps[path.basename(file)] = JSON.parse(xml2json.toJson(path.basename(file)))
        }
    });
console.log(maps)

for (var inst in maps) {

        try {
            articulations[inst] = maps[inst].InstrumentMap.member[1].list.obj[0].member[1].map(x=>x.string.value)
        } catch(err) {
            console.error(`failed to extract articulations from ${inst}.json:`)
            console.error(err)
        }
            
    }
    console.log('Extracted articulations:\n')
    console.log(articulations)
    console.log(maps)
});


// var result4 = JSON.parse(xml2json.toJson(files))
// var myExpression = [result4.InstrumentMap.member[1].list.obj[0].member[1].string.value]

Found a problem - there is a typo

if (path.extname(file) === '.expressionmap') {

note that the dot is needed otherwise if (path.extname(file) will always be false

1 Like

Coding by brute force here... next error appears below

// load expression maps
fs.readdir(dir, (err, files) => {
    if (err) { throw err }
    files.forEach(file => {
        console.log('path.extname(file) =' + path.extname(file))


        if (path.extname(file) === '.expressionmap') {
            console.log('path.extname(file) is expression map = TRUE')

            var mapName = path.basename(file)

            console.log('mapName = ' + mapName)

            maps[path.basename(file)] = JSON.parse(xml2json.toJson(path.basename(file)))
        }
    });
    console.log(maps)

    for (var inst in maps) {

        try {
            articulations[inst] = maps[inst].InstrumentMap.member[1].list.obj[0].member[1].map(x => x.string.value)
        } catch (err) {
            console.error(`failed to extract articulations from ${inst}.json:`)
            console.error(err)
        }

    }
    console.log('Extracted articulations:\n')
    console.log(articulations)
    console.log(maps)
});

HERO!!!

now i have this:

Can you post your latest code?

I think that the error lies with the directory structure - it's not getting the file properly and so there is no member where you need it.

I think that you need to put the for (var inst in maps) {
loop inside the files.forEach(file => { loop abd build each expression map at a time.

also - check the length of maps

const fs = nativeRequire('fs')
const path = nativeRequire('path')
const xml2json = nativeRequire('xml2json');


const dir = path.join('/Volumes/Audio/Steinberg/Cubase/Expression Maps/Native Instruments/Symphony Series');

const maps = {}
const articulations = {}

// load expression maps
fs.readdir(dir, (err, files) => {
    if (err) { throw err }
    files.forEach(file => {
        if (path.extname(file) === '.expressionmap') {
        
        maps[path.basename(file)] = JSON.parse(xml2json.toJson(path.basename(file)))
        }console.log(maps.length)
    });
    console.log(maps)

    for (var inst in maps) {

        try {
            articulations[inst] = maps[inst].InstrumentMap.member[1].list.obj[0].member[1].map(x => x.string.value)
        } catch (err) {
            console.error(`failed to extract articulations from ${inst}.json:`)
            console.error(err)
        }

    }
    console.log('Extracted articulations:\n')
    console.log(articulations)
    console.log(maps)
});

length of maps is times expression maps (in this case 19) 'undefined'

how can we console.log one of these json files?

Not sure...

i guess something's wrong with the json files but at the other hand with one expression map it worked.

i put the loop in the files.forEach section. still the same error

Getting a bit frustrated now -

I have exactly the same code as you except I have the following to my files:

const dir = path.join(__dirname, '../ExpressionMaps');

but I get the following which suggests there's a problem in my expression maps!