I need to parse a Google Alert RSS Feed with Google Apps Script.
Google Alerts RSS-Feed
I found a script which should do the job but I cant get it working with Google's RSS Feed:
The feed looks like this:
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:idx="urn:atom-extension:indexing">
<id>tag:google.com,2005:reader/user/06807031914929345698/state/com.google/alerts/10604166159629661594</id>
<title>Google Alert – garbe industrial real estate</title>
<link href="https://www.google.com/alerts/feeds/06807031914929345698/10604166159629661594" rel="self"/>
<updated>2022-03-17T19:34:28Z</updated>
<entry>
<id>tag:google.com,2013:googlealerts/feed:10523743457612307958</id>
<title type="html"><b>Garbe Industrial</b> plant Multi-User-Immobilie in Ludwigsfelde - <b>Property</b> Magazine</title>
<link href="https://www.google.com/url?rct=j&sa=t&url=https://www.property-magazine.de/garbe-industrial-plant-multi-user-immobilie-in-ludwigsfelde-117551.html&ct=ga&cd=CAIyGWRmNjU0ZGNkMzJiZTRkOWY6ZGU6ZGU6REU&usg=AFQjCNENveXYlfrPc7pZTltgXY8lEAPe4A"/>
<published>2022-03-17T19:34:28Z</published>
<updated>2022-03-17T19:34:28Z</updated>
<content type="html">Die <b>Garbe Industrial Real Estate</b> GmbH startet ihr drittes Neubauprojekt in der Metropolregion Berlin/Brandenburg. Der Projektentwickler hat sich ...</content>
<author>
...
</feed>
I want to extract entry -> id, title, link, updated, content.
I used this script:
function ImportFeed(url, n) {
var res = UrlFetchApp.fetch(url).getContentText();
var xml = XmlService.parse(res);
//var item = xml.getRootElement().getChild("channel").getChildren("item")[n - 1].getChildren();
var item = xml.getRootElement().getChildren("entry")[n - 1].getChildren();
var values = item.reduce(function(obj, e) {
obj[e.getName()] = e.getValue();
return obj;
}, {});
return [[values.id, values.title, values.link, values.updated, values.content]];
}
I modified this part, but all i got was "TypeError: Cannot read property 'getChildren' of undefined"
//var item = xml.getRootElement().getChild("channel").getChildren("item")[n - 1].getChildren();
var item = xml.getRootElement().getChildren("entry")[n - 1].getChildren();
Any idea is welcome!
In your situation, how about the following modified script?
Modified script:
function SAMPLE(url, n = 1) {
var res = UrlFetchApp.fetch(url).getContentText();
var root = XmlService.parse(res.replace(/&/g, "&")).getRootElement();
var ns = root.getNamespace();
var entries = root.getChildren("entry", ns);
if (!entries || entries.length == 0) return "No values";
var header = ["id", "title", "link", "updated", "content"];
var values = header.map(f => f == "link" ? entries[n - 1].getChild(f, ns).getAttribute("href").getValue().trim() : entries[n - 1].getChild(f, ns).getValue().trim());
return [values];
}
In this case, when you use getChild and getChildren, please use the name space. I thought that this might be the reason of your issue.
From your script, I guessed that you might use your script as the custom function. In that case, please modify the function name from ImportFeed to others, because IMPORTFEED is a built-in function of Google Spreadsheet. In this sample, SAMPLE is used.
If you want to change the columns, please modify header.
In this sample, the default value of n is 1. In this case, the 1st entry is retrieved.
In this script, for example, you can put =SAMPLE("URL", 1) to a cell as the custom function. By this, the result value is returned.
Note:
If the above-modified script was not the direct solution of your issue, can you provide the sample value of res? By this, I would like to modify the script.
As the additional information, when you want to put all values by executing the script with the script editor, you can also use the following script.
function myFunction() {
var url = "###"; // Please set URL.
var res = UrlFetchApp.fetch(url).getContentText();
var root = XmlService.parse(res.replace(/&/g, "&")).getRootElement();
var ns = root.getNamespace();
var entries = root.getChildren("entry", ns);
if (!entries || entries.length == 0) return "No values";
var header = ["id", "title", "link", "updated", "content"];
var values = entries.map(e => header.map(f => f == "link" ? e.getChild(f, ns).getAttribute("href").getValue().trim() : e.getChild(f, ns).getValue().trim()));
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set the sheet name.
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
}
References:
XML Service
map()
I have this string with xml extract in a tuple list:
MessageResponse = [{"code",0},{"description","description"},{"respuestaServicioSoap",{{"executeWebServiceSolutionResult",{{"CEDULARUCSpecified", false},{"AUTORIZACION", "00000012431781"},{"AUTORIZACIONSpecified",true},{"RESULTADO","000"},{"CODIGO_RESULTADOSpecified",true},{"COD_PAGO","00000012431781"},{"COD_PAGOSpecified",true},{"COMISION",{{"string","0"}}},{"COMISIONSpecified", true},{"DIRECCIONSpecified", false},{"FECHA_COMPENSACIONSpecified", false},{"FECHA_TRANSACCION","20170116"},{"FECHA_TRANSACCIONSpecified",true},{"FECHORA_SW","20170116123951"},{"FECHORA_SWSpecified",true},{"HORA_TRANSACCION","123951"},{"HORA_TRANSACCIONSpecified",true},{"MENSAJE","TRANSACCION OK"},{"MENSAJESpecified",true},{"NOMBRESpecified",false},{"PRODUCTO","0010761005"},{"PRODUCTOSpecified",true},{"SECUENCIA_ADQ","2833"},{"SECUENCIA_ADQSpecified",true},{"SECUENCIA_SW","576167"},{"SECUENCIA_SWSpecified",true},{"TERMINAL","0696069603000001"},{"TERMINALSpecified",true},{"TYPE_TRNSpecified",false},{"VALOR_TOTAL", { { "string", "0" }}},{"VALOR_TOTALSpecified",true},{"XML_ADDSpecified",false},{"XML_DATASpecified",false},{"XML_FACT","<XML_FACT>\r\n <DATOS_FACT>\r\n <LINEA_1>REPRESENTACIONES ORMAN S.A.</LINEA_1>\r\n <LINEA_2>RUC: 0987654321</LINEA_2>\r\n <LINEA_3 />\r\n <LINEA_4 />\r\n <LINEA_5>FACTURA: 001-627-0000048745</LINEA_5>\r\n <LINEA_6>CLAVE: </LINEA_6>\r\n <LINEA_7>COMISION POR SERVICIO</LINEA_7>\r\n <LINEA_8>RECAUDACION EEAAPP - CUENTA: 11223344</LINEA_8>\r\n <LINEA_12>FACTURA: 001-627-0000048745 - CONSULTE SU DOCUMENTO EN WWW.LITO.COM/DOCUMENTOSELECTRONICOS</LINEA_12>\r\n <MSGCOMP />\r\n <MSGFACT />\r\n </DATOS_FACT>\r\n</XML_FACT>"},{"XML_FACTSpecified",true},{"XML_REPLY_CONSULTASpecified",false},{"XML_REPLY_PAGOSSpecified",false}}},{"executeWebServiceSolutionResultSpecified", true}}},{"result", "ok"}]
and need to get the text in LINEA_5 tag, any idea how to do it?
with this code:
{Xml, _Rest} = xmerl_scan:string(XmlFactura).
[#xmlText{value=Linea5}] = xmerl_xpath:string("//LINEA_5/text()", Xml).
the OTP library xmerl provides all the functions to manipulate XML files or string. It provides a set of record that help to handle different elements.
documentation is available here
The records are defined in erlXX/lib/xmerl-YYY/include/xmerl.hrl:
#xmlText{}
#xmlElement{}
#xmlPI{}
#xmlComment{}
#xmlDecl{}
[edit]
The xml data that you provide in your example is already modified, so I take an example from my own. Consider an xml file with the content:
<?xml version="1.0" encoding="UTF-8"?> <package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="uuid_id">
<metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:opf="http://www.idpf.org/2007/opf" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:calibre="http://calibre.kovidgoyal.net/2009/metadata" xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:creator opf:role="aut" opf:file-as="Ahern, Cecelia">Cecelia Ahern</dc:creator>
<dc:publisher>J'ai Lu</dc:publisher>
<meta name="calibre:title_sort" content="Si tu me voyais maintenant"/>
<dc:description>description blah blah</dc:description>
<meta name="calibre:timestamp" content="2012-03-18T18:04:20+00:00"/>
<dc:title>Si tu me voyais maintenant</dc:title>
<meta name="cover" content="cover"/>
<dc:date>2012-03-18T18:04:23+00:00</dc:date>
<dc:contributor opf:role="bkp">calibre (0.8.42) [http://calibre-ebook.com]</dc:contributor>
<dc:identifier opf:scheme="ISBN">9782290006504</dc:identifier>
<dc:identifier id="uuid_id" opf:scheme="uuid">7d062b17-258e-4268-9d46-a753c063c969</dc:identifier>
<dc:subject>Chick-lit</dc:subject>
<meta name="calibre:user_categories" content="{}"/>
<meta name="calibre:author_link_map" content="{"Cecelia Ahern": ""}"/>
<dc:language>fr</dc:language>
</metadata>
<manifest>
<item href="cover.jpeg" id="cover" media-type="image/jpeg"/>
</manifest>
<spine toc="ncx">
<itemref idref="titlepage"/>
</spine>
<guide>
<reference href="titlepage.xhtml" type="cover" title="Cover"/>
</guide> </package>
It is extract from an epub book, and stored in a file "content.opf". If I want to get the author name (line 4) I can do:
1> rr("C:\\My programs\\erl8.2\\lib\\xmerl-1.3.12\\include\\xmerl.hrl").
2> {Xml,_} = xmerl_scan:file("../doc/content.opf"),
2> Content = Xml#xmlElement.content,
2> [MetaRec] = [X || X <- Content, X#xmlElement.name == metadata],
2> Meta = MetaRec#xmlElement.content,
2> [CreatRec] = [X || X <- Meta, X#xmlElement.name == 'dc:creator'],
2> Creat = CreatRec#xmlElement.content,
2> [CreatText] = [X || X <- Creat, is_record(X,xmlText)],
2> Aut = CreatText#xmlText.value.
"Cecelia Ahern"
I am using the below mentioned code to get the content of a specific tag, but when I am trying to execute it I am getting some extra data along with it, I don't understand why is it happening. Lets say if I search for title tag then I am getting " [echo] Title : <title>Unit Test Results</title>,Unit Test Results" this as result, but the problem is title only contains "<title>Unit Test Results</title>" why this extra ",Unit Test Results" thing is coming.
<project name="extractElement" default="test">
<!--Extract element from html file-->
<scriptdef name="findelement" language="javascript">
<attribute name="tag" />
<attribute name="file" />
<attribute name="property" />
<![CDATA[
var tag = attributes.get("tag");
var file = attributes.get("file");
var regex = "<" + tag + "[^>]*>(.*?)</" + tag + ">";
var patt = new RegExp(regex,"g");
project.setProperty(attributes.get("property"), patt.exec(file));
]]>
</scriptdef>
<!--Only available target...-->
<target name="test">
<loadfile srcFile="E:\backup\latest report\Report-20160523_2036.html" property="html.file"/>
<findelement tag="title" file="${html.file}" property="element"/>
<echo message="Title : ${element}"/>
</target>
The return value of RegExp.exec() is an array. From the Mozilla documentation on RegExp.prototype.exec():
The returned array has the matched text as the first item, and then
one item for each capturing parenthesis that matched containing the
text that was captured.
If you add the following code to your JavaScript...
var patt = new RegExp(regex,"g");
var execResult = patt.exec(file);
print("execResult: " + execResult);
print("execResult.length: " + execResult.length);
print("execResult[0]: " + execResult[0]);
print("execResult[1]: " + execResult[1]);
...you'll get the following output...
[findelement] execResult: <title>Unit Test Results</title>,Unit Test Results
[findelement] execResult.length: 2
[findelement] execResult[0]: <title>Unit Test Results</title>
[findelement] execResult[1]: Unit Test Results
I am attempting to implement a Quickbooks Web connector (QBWC) in Railo 4.x
<cfcomponent output="false">
<cffunction name = "authenticate" access="remote" returntype="string">
<cfargument name = "username" type="string" required="true">
<cfargument name = "password" type = "string" required="true">
<cfset var loc = {}>
<cfset loc.retVal= []>
<cfset loc.retVal[1] = "MYSESSIONTOKEN">
<cfset loc.retVal[2] = "NONE">
<cfset loc.retVal[3] = "">
<cfset loc.retVal[4] = "">
<cfreturn loc.retVal >
</cffunction>
<cffunction name = "clientVersion" access="remote" returnType ="string">
<cfargument name = "productVersion" type="string" required="true">
<cfset var loc = {}>
<cfset loc.retVal = "">
<cfreturn loc.retVal>
</cffunction>
</cfcomponent>
This is my QWC file:
<?xml version="1.0"?>
<QBWCXML>
<AppName>QuickCellarSVC</AppName>
<AppID></AppID>
<AppURL>http://localhost:8080/QuickCellar.cfc</AppURL>
<AppDescription>Quick Cellar railo component</AppDescription>
<AppSupport>http://localhost:8080/support.cfm</AppSupport>
<UserName>Joe</UserName>
<OwnerID>{57F3B9B1-86F1-4fcc-B1EE-566DE1813D20}</OwnerID>
<FileID>{90A44FB5-33D9-4815-AC85-BC87A7E7D1EB}</FileID>
<QBType>QBFS</QBType>
<Scheduler>
<RunEveryNMinutes>2</RunEveryNMinutes>
</Scheduler>
</QBWCXML>
The QBWC trace shows the problem :
Object reference not set to an instance of an object.
More info:
StackTrace = at QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = QBWebConnector
I was able to drill down a little more and discover that there is a casting problem in Railo maybe?
<?xml version="1.0" encoding="UTF-8"?>
-<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">-<soap:Body>-
Can't cast Complex Object Type Struct to StringUse Built-In-Function "serialize(Struct):String" to create a String from Struct
Now I know some of you are thinking "just serialize" the struct. Well, there is no such function in Railo (that I know of).
Any ideas are greatly appreciated.
The first issue I see is your "authenticate" method has return type of string, but you are returning an array. If you are trying to return a string you could use return serializeJSON(loc.retVal) instead of just retVal, which would return it as a JSON formatted string.
I have this xml :
<document-display>
<name>
<entry lang="nl">nl Text</entry>
<entry lang="fr">fr Text</entry>
<entry lang="en">en Text</entry>
</name>
</document-display>
I would like to get the text according to the langage.
I'm using XmlSlurper.
With my current code :
def parsedD = new XmlSlurper().parse(xml)
parsedD."document-display".name.entry.each {it.#lang == 'fr'}
I have as bad result which is the concatenation of the 3 text content :
nl Textfr Texten Text
Thanks for helping.
Try
parsedD.name.entry.find { it.#lang == 'fr' }?.text()