My .XMl is
<?xml version="1.0" encoding="utf-8"?>
<data>
<shell id="TX-alg1-title">Lesson 2.1</shell>
<options id="parent">
<option id="TX-alg1">TX16E_ISE_0005</option>
<option id="TX-alg1-CID">9780353053</option>
</options>
</data>
I wanted to add another shell tag after shell tag previously present in xml.
Expected O/p
<?xml version="1.0" encoding="utf-8"?>
<data>
<shell id="TX-alg1-title">Lesson 2.1</shell>
<shell id="CA-int1-title">Lesson 2.1</shell>
<options id="parent">
<option id="TX-alg1">TX16E_ISE_0005</option>
<option id="TX-alg1-CID">9780353053</option>
</options>
</data>
I am reading my .XML file in app.js as
fs.readFile( './dlo_custom_en-US.xml', function(err, data) {
});
Please advise how to append shell tag after already present shell tag in nodejs.
question is almost similar Regex match text between tags
node is noting except javascript at server side. almost all programming languages have regexp to find patterns. here is simplest solution but you should to study more about regexp
fs.readFile( './dlo_custom_en-US.xml', function(err, data) {
data.replace(/\<shell(.)*\<\/shell>/, "new replacement here")
});
***** updated *****
from JavaScript: How can I insert a string at a specific index
var fs =require('fs')
String.prototype.splice = function(idx, rem, str) {
return this.slice(0, idx) + str + this.slice(idx + Math.abs(rem));
};
fs.readFile( './dlo_custom_en-US.xml',"utf8", function(err, data) {
if(err) return
var index = data.lastIndexOf('</shell>')+8
console.log(index)
var data= data.splice(index,0, 'newwwwwwwwwww')
console.log(data)
fs.writeFile('./new.xml',data,(err, done)=>{
if(err) return
console.log(err, done)
})
});
Related
I need to convert a json to xml with saxonjs, I don't know how to match keys to xml nodes, I'm looking for some examples for none of them work for me, this is my code
const issue = {
id: 1,
details: {
type: 'urgent',
description: 'Description of issue comes here',
date: '2021-12-12',
}
};
saxonJS.transform({
stylesheetLocation: './issue.sef.json',
sourceType: 'json',
sourceText: issue,
destination: 'serialized',
}, 'async').then(data => {
fs.open('output.xml', 'w', function(err, fd) {
fs.write(fd, data.principalResult, (err2, bytes) => {
if(err2) {
console.log(err2);
}
});
});
res.status(200).send('Ok');
})
.catch(err => {
console.log(err);
res.status(500).send('error');
});
And this is the output I'm trying to achieve
<xml>
<issue id="1">
<description>
<![CDATA[
Description of issue comes here
]]>
</description>
<type>urgent</type>
<date>2021-12-12</date>
</issue>
</xml>
Can you please help me with the xslt template?
Your shown input is a JavaScript object, it is not JSON in the strict syntax rules of the JSON spec.
So I would think it is better to use JSON.stringify to create JSON and pass that to the XPath 3.1 function parse-json to create JSON or to make use of the Saxon-JS 2.3 feature to take JSON text, just make sure you have correctly JSON.stringifyed that object.
As for a sample XSLT, that looks easy, for readability of the XSLT the below sample just uses a JavaScript string with the XSLT source code and runs it through the Saxon API:
const SaxonJS = require("saxon-js");
const issue = {
id: 1,
details: {
type: 'urgent',
description: 'Description of issue comes here',
date: '2021-12-12',
}
};
const xslt = `<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" expand-text="yes">
<xsl:output indent="yes" cdata-section-elements="description"/>
<xsl:template match=".">
<xml>
<issue id="{?id}">
<description>{?details?description}</description>
<type>{?details?type}</type>
<date>{?details?date}</date>
</issue>
</xml>
</xsl:template>
</xsl:stylesheet>`;
const result = SaxonJS.XPath.evaluate(`transform(map {
'stylesheet-text' : $xslt,
'initial-match-selection' : parse-json($json),
'delivery-format' : 'serialized'
})?output`,
[],
{ params :
{
json : JSON.stringify(issue),
xslt : xslt
}
});
Of course, in the end you can first compile the XSLT to SEF/JSON and then run it as you tried.
To give you an example XSLT that uses two different templates and apply-templates, the following, instead of processing the nested object/map with inline code pushes processing it to a different template:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" expand-text="yes" xmlns:map="http://www.w3.org/2005/xpath-functions/map" exclude-result-prefixes="#all">
<xsl:output indent="yes" cdata-section-elements="description"/>
<xsl:template match=".[. instance of map(*) and map:contains(., 'id')]">
<xml>
<issue id="{?id}">
<xsl:apply-templates select="?details"/>
</issue>
</xml>
</xsl:template>
<xsl:template match=".[. instance of map(*) and map:contains(., 'description')]">
<description>{?description}</description>
<type>{?type}</type>
<date>{?date}</date>
</xsl:template>
</xsl:stylesheet>
Pls be gentle!. Newbe having a go. I am using node.js (for the first time)
I have a large (10,000 line) XML file that I need to rip through and generate about 900 rows across 50 columns in smartsheets. I need to retain the order that comes from the XML file (important).
I have the code working so that it reads the xml file, and can write to the rows/columns but obviously I am generating the update inputs faster than smartsheet can handle, so I tried promises. I just can't seem to crack it and would appreciate any help you can give. The system generates all of the records but chokes as it tries to write them to smasrtsheet AND the order is all stuffed up.
Happy to be told I am barking up the wrong tree if you can suggest a better way.
Thanks in advance.
Jerji.
3 blocks of code:
testing.js file (the script itself)
testing.xml (a VERY cut down version of the xml file)
testing.xsd (the xml schema file).
testing.js
// Initialize the client
var client = require('smartsheet');
var smartsheetClient = client.createClient({
accessToken: '<insert your own access token before you run>', // use your access code
logLevel: 'info'
});
var fs= require('fs'),
xml2js = require('xml2js');
const parser = new xml2js.Parser();
const xpath = require('xpath'),
dom = require('xmldom').DOMParser;
fs.readFile('testing.xml',function(err , data){
var doc = new dom().parseFromString(data.toString(), 'text/xml');
var select = xpath.useNamespaces('testing.xsd');
if(err){
//display error
}
else{
for (var i=0; i < 10 ; i++ ){
var rowcounter=i+1;
var identifier = select('//Identifier/text()', doc)[i].nodeValue;
var revision = select('//Revision/text()', doc)[i].nodeValue;
var updated = select('//Updated/text()', doc)[i].nodeValue;
var description = select('//Description/text()', doc)[i].nodeValue;
var row = [{
"toBottom": true,
"cells": [
// Note that the column Ids here are samples. Adjust as required.
{"columnId": 2461535086897028, "value": rowcounter, "strict": false},
{"columnId": 6965134714267524, "value": identifier, "strict": false},
{"columnId": 1335635180054404, "value": description, "strict": false},
{"columnId": 7457715923511172, "value": revision, "strict": false},
{"columnId": 1828216389298052, "value": updated, "strict": false},
{"columnId": 7176240946800516, "value": 'Marker', "strict": false},
]
}];
writeRow(row);
sleep();
}
}
);
// DUMMY SLEEP FUNCTION
var sleep = function () {
let now = Date.now(), end = now + 3000;
while (now < end) { now = Date.now(); }
};
// Function to write row to sheet.
function writeRow(row) {
var options = {
sheetId: <insert your own sheet ID here>, //note real sheet id needed
body: row
};
return new Promise((resolve, reject) => {
try {
let obj = smartsheetClient.sheets.addRows(options);
resolve(obj);
} catch (err) {
reject(err);
};
});
let myPromise = smartsheetClient.sheets.addRows(options);
myPromise.then(data => {
console.log("Line Written :", data);
}).catch(err => {
console.log(err);
});
}
testing.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- June 2021 -->
<DOCUMENT>
<ITEM>
<Identifier>2021-91</Identifier>
<Revision>5</Revision>
<Updated>Oct-20</Updated>
<Description>Item Description 1.</Description>
</ITEM>
<ITEM>
<Identifier>2021-97</Identifier>
<Revision>1</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 2.</Description>
</ITEM>
<ITEM>
<Identifier>2020-14</Identifier>
<Revision>0</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 3.</Description>
</ITEM>
<ITEM>
<Identifier>2019-44</Identifier>
<Revision>2</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 4.</Description>
</ITEM>
<ITEM>
<Identifier>2021-06</Identifier>
<Revision>2</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 5.</Description>
</ITEM>
<ITEM>
<Identifier>2019-13</Identifier>
<Revision>2</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 6.</Description>
</ITEM>
<ITEM>
<Identifier>2020-03</Identifier>
<Revision>2</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 7.</Description>
</ITEM>
<ITEM>
<Identifier>2021-19</Identifier>
<Revision>2</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 8.</Description>
</ITEM>
<ITEM>
<Identifier>2019-56</Identifier>
<Revision>0</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 9.</Description>
</ITEM>
<ITEM>
<Identifier>2020-15</Identifier>
<Revision>3</Revision>
<Updated>Oct-20</Updated>
<Description>Item description 10.</Description>
</ITEM>
</DOCUMENT><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
testing.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="DOCUMENT">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="ITEM">
<xs:complexType>
<xs:sequence>
<xs:element name="Identifier" type="xs:unsignedShort" />
<xs:element name="Revision" type="xs:unsignedByte" />
<xs:element name="Updated" type="xs:string" />
<xs:element name="Description" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Any advice would be most appreciated.
Problem
Promise is asynchronous API which has it's own independant context.
It has 3 statuses, which are pending, resolve and reject.
When the Promise is resolved, it calls .then(cb) and in case it failed, which is reject, it calls .catch(cb) internally.
first of all, you didn't wait for Promise to be done either way that it be resolved or rejected.
You should use .then() and .catch() to wait for it be done. Maybe async/await API will be even better for doing that.
Solution
Standard way to implement delay function
const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms)
writeRow()
function writeRow(row) {//Return your promise and let it be controlled outside of function
var options = {
sheetId: < insert your own sheet ID here > , //note real sheet id needed
body: row
};
return new Promise((resolve, reject) => {
try {
let obj = smartsheetClient.sheets.addRows(options);
resolve(obj);
} catch (err) {
reject(err);
};
});
}
runner : wrap your logic into async function to use await API.
(or you can just use traditional way to control promise with .then(), .catch())
async function runner(){
...your scripts...
for (var i = 0; i < 10; i++) {
...
await writeRow(row)
await sleep(3000)//write row and wait for 3 seconds
...
}
}
...your scripts...
}
runner()
You have to know that
Smartsheet API doesn't support simultaneous calls for a given token.
Smartsheet API
can insert/update multiple rows with a single call like 100 rows
with a single call.
So change the strucure of your solution :
Read your source and build the list of smartsheet rows to insert/update.
Split that list of rows per 100 rows blocks.
Insert/update per 100 rows
I have an xml like this but i want to convert the xml into proper xml by node.js can anyone help me in this
<?xml version = 1.0 encoding = utf-8?>
<!-- xslplane.1.xml -->
<?xml-stylesheet type = text/xsl href = xslplane.1.xsl ?>
<plane>
<year> 1977 </year>
<make> Cessna </make>
<model> Skyhawk </model>
<color> Light blue and white </color>
</plane>
I want XML like this with all the possible quotations
<?xml version = "1.0" encoding = "utf-8"?>
<!-- xslplane.1.xml -->
<?xml-stylesheet type = "text/xsl" href = "xslplane.1.xsl" ?>
<plane>
<year> 1977 </year>
<make> Cessna </make>
<model> Skyhawk </model>
<color> Light blue and white </color>
</plane>
You can try using xml2js to convert your malformed xml to JSON and use it again to convert to xml. Try the following code.
let xml2js = require('xml2js');
var xml = "<hi>Hello xml2js!</hi>";
xml2js.parseString(xml, function (err, result) {
console.dir(result);
var builder = new xml2js.Builder();
var xml = builder.buildObject(result);
console.log(xml)
});
Update : Direct File read
var parser = new xml2js.Parser();
fs.readFile(__dirname + '/foo.xml', function(err, data) {
parser.parseString(data, function (err, result) {
console.dir(result);
console.log('Done');
var builder = new xml2js.Builder();
var xml = builder.buildObject(result);
console.log(xml)
});
});
Hi I am trying to get the user profile properties from sharepoint on client side with javascript.But I am not getting the value of nodes in xml.
How to get them. the xml will look like as:
How to get attribute value of node in xml using xpath
Here I want to get the value which is between <name> tags <Name>AccountName</Name> and between Name tags
want to get the value = abc what will be the xpath expression
Please help
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserProfileByNameResponse xmlns="http://microsoft.com/webservices/SharePointPortalServer/UserProfileService">
<GetUserProfileByNameResult>
<Pro pertyData>
<IsPrivacyChanged>false</IsPrivacyChanged>
<IsValueChanged>false</IsValueChanged>
<Name>UserProfile_GUID</N ame>
<Privacy>NotSet</Privacy>
<Values>
<ValueData>
<Value xmlns:q1="http://microsoft.com/wsdl/types/" xsi:type="q1:guid">8ed84415-7330-4857-a7d2- d797d71c439f
</Value>
</ValueData>
</Values>
</PropertyData>
<PropertyData>
<IsPrivacyChanged>false</IsPrivacyChanged>
<Is ValueChanged>false</IsValueChanged>
<Name>AccountName</Name>
<Privacy>NotSet</Privacy>
<Values>
<ValueData>
<Value xsi:type="xsd:string">abc
</Value>
</ValueData>
</Values>
</PropertyData>
</GetUserProfileByNameResult>
</GetUserProfileByNameResponse>
</ soap:Body>
</soap:Envelope>
Please help me in this.
var propertyData = $(responseXML).find("PropertyData").filter(function(e){
return $(this).find("Name").text() == "AccountName";
});
var value = propertyData.length > 0 ? propertyData.find('Value').text() : '';
Since you are trying to retrieve user profile via SharePoint Web Services I would recommend to utilize SPServices library, it hides (almost)all the intricacies when working with SharePoint Web Services from JavaScript. The following example demonstrates how to retrieve user profile using GetUserProfileByName method and process the results:
function getUserProfile(accountName,completeFn) {
var userInfo = {};
$().SPServices({
AccountName: accountName,
operation: 'GetUserProfileByName',
completefunc: function (xData, Status) {
$(xData.responseXML).SPFilterNode("PropertyData").each(function() {
userInfo[$(this).find("Name").text()] = $(this).find("Value").text();
});
completeFn(userInfo);
}
});
}
var loginName = 'i:0#.f|membership|username#contoso.onmicrosoft.com';
getUserProfile(loginName,function(info){
console.log(info);
});
You have to traverse through the xml nodes returned from the SPServices. I have written a function for getting the desired user profile property.
function getUPValue(x, p) {
var thisValue = $(x).SPFilterNode("PropertyData").filter(function() {
return $(this).find("Name").text() == p;
}).find("Values").text();
return thisValue;
}
Further to query the user property you just need to call like below,
getUPValue(xData.responseXML, "WorkEmail");
These article provides a detail overview of it over here
I have a (probably very stupid) question.
I have a form I submit to my nodeJS server with Express.
This works perfectly with text inputs and radiobuttons, but now I have to add a select.
The server does not give an error but the select is not parsed properly.
my code:
<select id="chooselang">
<option value="nl" name="language">NL</option>
<option value="en" name="language">EN</option>
</select>
and my server looks like this:
app.post('/settings', function(req, res){
// Fill JSON array with new settings
var myData = {
,name : req.body.name
,mail : req.body.email
,language : req.body.language
,location: req.body.location
}
// Write to JSON file
fs.writeFile(configfilepath, JSON.stringify(myData, null, 4), function(err) {
if(err) {
res.send(500);
console.log(err);
} else {
setTimeout(function () {
res.redirect('back');
}, 2000)
}
});
});
Could someone please tell me what I'm doing wrong?
Probably you will need to add a name attribute in your select and use that to capture the values.
Also, only one of the option values will be sent to the server, so there is no point in assigning name to each one of the options, if that was your intention.