使用 Apps 脚本获取 Confluence 页面的内容并解析其内容
Get Content of a Confluence page with Apps Script and parse its content
我找到了一个类似的 用于在 confluence 中创建一个新页面,但不是一个用于获取 confluence 云页面内容的特定的,例如在 Google 应用程序脚本中基于 ID并能够解析页面正文的内容,例如,解析 JSON 结果或者可能使用 Confluence REST-API 来获取特定对象的内容。
我将上述问题的源代码改编如下:
function myFunction() {
const url = "https://<company>.atlassian.net/wiki/rest/api/content/<ID>";
const token = "<token>";
const user = "<email>";
headers = { "Authorization": "Basic " + Utilities.base64Encode(user + ':' + token) };
var params = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": false,
"contentType": "application/json"
};
let createResponse = UrlFetchApp.fetch(url, params);
console.log(createResponse.getContentText());
}
其中 <xxxx>
是与我的帐户相关的特定参数。 <ID>
是 Confluence 文档 ID。
我关注REST API specification for Confluence Cloud
我收到了回复,但它提供了有关该页面的一般信息属性。
将 url 更改为以下内容:
https://<company>.atlassian.net/wiki/rest/api/content/<ID>?expand=body.storage
添加以下后缀:?expand=body.storage
生成内容,但解析困难:
{"id":"2020706439","type":"page","status":"current","title":"Onboard Resource Template for
more than one resource","macroRenderedOutput":{},"body":{"storage":{"value":"<ac:structured-macro ac:name=
\"info\" ac:schema-version=\"1\" ac:macro-id=\"756d4d54-7492-49ac-b502-19d1a740ea92\"><ac:rich-text-body><p>
To use it, please make a copy of this template and replace the title with Resource Name(s) and add the
onboarding date as a suffix</p></ac:rich-text-body></ac:structured-macro><table data-layout=\"wide\">
<colgroup><col style=\"width: 182.0px;\" /><col style=\"width: 144.0px;\" /><col style=\"width: 148.0px;\" />
<col style=\"width: 143.0px;\" /><col style=\"width: 137.0px;\" /><col style=\"width: 142.0px;\" />
</colgroup><tbody><tr><td data-highlight-colour=\"#6fa8dc\" colspan=\"6\"><p style=\"text-align: center;\">
<strong>New Resource (s) Onboarding Information and Tracking</strong></p></td></tr>
<tr><td data-highlight-colour=\"#ff9900\"><p>Information Provided by Vendor</p></td>
<td data-highlight-colour=\"#ff9900\"><p>Resource 1</p></td><td data-highlight-colour=\"#ff9900\">
<p>Resource 2</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 3</p></td><td data-highlight-colour=\"#ff9900\">
<p>Resource 4</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 5</p></td></tr><tr><td><p>First
Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Last
Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Address</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Phone Number</p></td><td>
<p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>E-Mail</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>WFH or W@Office</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Location (if W@Office)</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Role</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Start Date</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>End Date</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Name</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Contact Name</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Phone Number</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Manager's Name</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Team</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#b6d7a8\" colspan=\"6\">
<p>Information Provided by Onboarding Manager</p></td></tr><tr><td><p>New Resource ID</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>New
Resource Company E-mail</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td></tr><tr><td><p>Cost Center</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Laptop Serial Number</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#b6d7a8\">
<p><ac:inline-comment-marker ac:ref=\"377a17e3-a869-451f-a58b-19cac76916a4\">Access Requests by
Rosana</ac:inline-comment-marker></p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">
Ticket Number</p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Date </p><p style=\"text-align: center;\">
Submitted</p></td><td data-highlight-colour=\"#b6d7a8\"><p>SNOW Assignee</p></td>
<td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">
Ready in<ac:inline-comment-marker ac:ref=\"269ae226-6036-4ede-9720-d3c25f5d31d2\"> </ac:inline-comment-marker>(n)-Days</p></td>
<td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Date Completed</p></td></tr><tr><td><p>Company ID Request</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Laptop</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Slack</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td>
<p>Outlook</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>WebEx</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Ping</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#a2c4c9\" colspan=\"6\"><p>Access Request by
Program Manager (or a PM on his behalf)</p></td></tr><tr><td><p>SNOW Access and Timesheets</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#f4cccc\" colspan=\"6\">
<p>Access Request/Action by David Leal</p></td></tr><tr><td><p>Access to Jira/Confluence</p></td>
<td><p /></td><td><p /></td><td><p>Jira Admin</p></td><td><p /></td><td><p /></td></tr>
<tr><td><p>Resource Plan</p></td><td><p /></td><td><p /></td><td><p>Snow Manager</p></td>
<td><p /></td><td><p /></td></tr>
<tr><td><p><em>Actions</em></p></td><td data-highlight-colour=\"#f4f5f7\" colspan=\"5\"><p style=\"text-align: center;\">
<em> Date Completed</em></p></td></tr><tr><td><p style=\"text-align: right;\">Add to Slack Channels</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr>
<td><p style=\"text-align: right;\">Add to JIRA Projects</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr>
<tr><td data-highlight-colour=\"#fff2cc\"><p>Access Requests by Tech Lead</p></td>
<td data-highlight-colour=\"#fff2cc\"><p>Ticket Number</p></td><td data-highlight-colour=\"#fff2cc\"><p>Date Submitted</p></td>
<td data-highlight-colour=\"#fff2cc\"><p>SNOW Assginee</p></td><td data-highlight-colour=\"#fff2cc\"><p>Ready in Days</p></td>
<td data-highlight-colour=\"#fff2cc\"><p>Date Completed</p></td></tr><tr><td><p>AWS Work Space (VDI)</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>GitLab</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>AWS Console</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td></tr></tbody></table><p />",
"representation":"storage","embeddedContent":[],"_expandable":{"content":"/rest/api/content/2020706439"}},
"_expandable":{"editor":"","atlas_doc_format":"","view":"","export_view":"","styled_view":"","dynamic":"",
"editor2":"","anonymous_export_view":""}},"extensions":{"position":158},"_expandable":{"childTypes":"","container":
"/rest/api/space/PDC","metadata":"","operations":"","schedulePublishDate":"","children":"/rest/api/content/2020706439/child",
"restrictions":"/rest/api/content/2020706439/restriction/byOperation","history":"/rest/api/content/2020706439/history",
"ancestors":"","version":"","descendants":"/rest/api/content/2020706439/descendant","space":
"/rest/api/space/PDC"},"_links":{"editui":"/pages/resumedraft.action?draftId=2020706439","webui":
"/spaces/PDC/pages/2020706439/Onboard+Resource+Template+for+more+than+one+resource","context":"/wiki",
"self":"https://<company>.atlassian.net/wiki/rest/api/content/2020706439","tinyui":"/x/h4hxe","collection":
"/rest/api/content","base":"https://pan-american.atlassian.net/wiki"}}
我想获得的内容是合流 table 的一部分,如下所示:
关于这个问题,有以下问题:
- 这是获取 Confluence 页面内容以解析它的最佳方法吗?例如使用选项:
expand=body.storage
或者相反,有更好的方法来获取 Confluence 页面的内容(或特定的table),所以更容易解析。
- 如果得到的内容是最好的方法,那么有没有HTMLtablejavascript库或者工具或者脚本来解析table内容?
我相信你的目标如下。
- 您想从问题中的示例值 (
it generates the content, but it is difficult to parse:
) 中解析 HTML,并将它们放入 sheet。
- 您已经能够从要使用的 API 中检索值。
在这种情况下,下面的示例脚本怎么样?在这种情况下,我想建议使用 Sheets API。 Sheets API 的 pasteData 可以解析 HTML table.
示例脚本:
请将以下脚本复制并粘贴到 Google Spreadsheet 的脚本编辑器中。而且,此脚本使用 Sheets API。所以please enable Sheets API at Advanced Google services。并且,请设置 sheet 名称。和 运行 功能。这样,Sheets API 解析 HTML table 并放入 sheet.
function myFunction() {
const obj = { "id": "2020706439", "type": "page", "status": "current", "title": "Onboard Resource Template for more than one resource", "macroRenderedOutput": {}, "body": { "storage": { "value": "<ac:structured-macro ac:name=\"info\" ac:schema-version=\"1\" ac:macro-id=\"756d4d54-7492-49ac-b502-19d1a740ea92\"><ac:rich-text-body><p>To use it, please make a copy of this template and replace the title with Resource Name(s) and add the onboarding date as a suffix</p></ac:rich-text-body></ac:structured-macro><table data-layout=\"wide\"><colgroup><col style=\"width: 182.0px;\" /><col style=\"width: 144.0px;\" /><col style=\"width: 148.0px;\" /><col style=\"width: 143.0px;\" /><col style=\"width: 137.0px;\" /><col style=\"width: 142.0px;\" /></colgroup><tbody><tr><td data-highlight-colour=\"#6fa8dc\" colspan=\"6\"><p style=\"text-align: center;\"><strong>New Resource (s) Onboarding Information and Tracking</strong></p></td></tr><tr><td data-highlight-colour=\"#ff9900\"><p>Information Provided by Vendor</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 1</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 2</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 3</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 4</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 5</p></td></tr><tr><td><p>First Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Last Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Address</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Phone Number</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>E-Mail</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>WFH or W@Office</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Location (if W@Office)</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Role</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Start Date</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>End Date</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Contact Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Phone Number</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Manager's Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Team</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#b6d7a8\" colspan=\"6\"><p>Information Provided by Onboarding Manager</p></td></tr><tr><td><p>New Resource ID</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>New Resource Company E-mail</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Cost Center</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Laptop Serial Number</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#b6d7a8\"><p><ac:inline-comment-marker ac:ref=\"377a17e3-a869-451f-a58b-19cac76916a4\">Access Requests by Rosana</ac:inline-comment-marker></p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Ticket Number</p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Date </p><p style=\"text-align: center;\">Submitted</p></td><td data-highlight-colour=\"#b6d7a8\"><p>SNOW Assignee</p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Ready in<ac:inline-comment-marker ac:ref=\"269ae226-6036-4ede-9720-d3c25f5d31d2\"> </ac:inline-comment-marker>(n)-Days</p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Date Completed</p></td></tr><tr><td><p>Company ID Request</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Laptop</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Slack</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Outlook</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>WebEx</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Ping</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#a2c4c9\" colspan=\"6\"><p>Access Request by Program Manager (or a PM on his behalf)</p></td></tr><tr><td><p>SNOW Access and Timesheets</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#f4cccc\" colspan=\"6\"><p>Access Request/Action by David Leal</p></td></tr><tr><td><p>Access to Jira/Confluence</p></td><td><p /></td><td><p /></td><td><p>Jira Admin</p></td><td><p /></td><td><p /></td></tr><tr><td><p>Resource Plan</p></td><td><p /></td><td><p /></td><td><p>Snow Manager</p></td><td><p /></td><td><p /></td></tr><tr><td><p><em>Actions</em></p></td><td data-highlight-colour=\"#f4f5f7\" colspan=\"5\"><p style=\"text-align: center;\"><em> Date Completed</em></p></td></tr><tr><td><p style=\"text-align: right;\">Add to Slack Channels</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p style=\"text-align: right;\">Add to JIRA Projects</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#fff2cc\"><p>Access Requests by Tech Lead</p></td><td data-highlight-colour=\"#fff2cc\"><p>Ticket Number</p></td><td data-highlight-colour=\"#fff2cc\"><p>Date Submitted</p></td><td data-highlight-colour=\"#fff2cc\"><p>SNOW Assginee</p></td><td data-highlight-colour=\"#fff2cc\"><p>Ready in Days</p></td><td data-highlight-colour=\"#fff2cc\"><p>Date Completed</p></td></tr><tr><td><p>AWS Work Space (VDI)</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>GitLab</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>AWS Console</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr></tbody></table><p />", "representation": "storage", "embeddedContent": [], "_expandable": { "content": "/rest/api/content/2020706439" } }, "_expandable": { "editor": "", "atlas_doc_format": "", "view": "", "export_view": "", "styled_view": "", "dynamic": "", "editor2": "", "anonymous_export_view": "" } }, "extensions": { "position": 158 }, "_expandable": { "childTypes": "", "container": "/rest/api/space/PDC", "metadata": "", "operations": "", "schedulePublishDate": "", "children": "/rest/api/content/2020706439/child", "restrictions": "/rest/api/content/2020706439/restriction/byOperation", "history": "/rest/api/content/2020706439/history", "ancestors": "", "version": "", "descendants": "/rest/api/content/2020706439/descendant", "space": "/rest/api/space/PDC" }, "_links": { "editui": "/pages/resumedraft.action?draftId=2020706439", "webui": "/spaces/PDC/pages/2020706439/Onboard+Resource+Template+for+more+than+one+resource", "context": "/wiki", "self": "https://<company>.atlassian.net/wiki/rest/api/content/2020706439", "tinyui": "/x/h4hxe", "collection": "/rest/api/content", "base": "https://pan-american.atlassian.net/wiki" } };
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName("Sheet1"); // Please set the sheet name.
const requests = [{ pasteData: { data: obj.body.storage.value, html: true, coordinate: { sheetId: sheet.getSheetId() } } }];
Sheets.Spreadsheets.batchUpdate({requests}, ss.getId());
// When you want to retrieve the values as an array, please use the following script.
// const array = sheet.getDataRange().getValues();
// console.log(array)
}
结果:
当此脚本为运行时,得到如下结果
注:
- 此示例脚本使用您的示例值。因此,当值的结构发生变化时,此脚本可能无法使用。所以请注意这一点。
- 我可以确认当我使用你的样本值时这个脚本工作正常。所以当您测试此脚本的实际值时,当出现错误时,请再次检查检索到的值。
参考文献:
这里有一个可能的解决方案,使用正则表达式从 createResponse.getContentText()
中提取信息。它不如@Tanaike 提供的解决方案通用,但它不需要在活动 Spreadsheet 上生成辅助选项卡(sheet),在获取所有记录后需要将其删除:
/*
@param id {String} Confluence ID page
*/
function getOnboardRecords(id) {
const URL = https://<COMPANY>.atlassian.net/wiki/rest/api/content/%s?expand=body.storage;
const TOKEN = "Provide the token";
const USER = "Provide user name, i.e an email";
// Relevant columns to get the information
const ROW_NAMES = ["First Name", "Last Name", "Phone Number",
"E-Mail", "Role", "Start Date", "End Date", "Vendor's Name",
"Team", "New Resource ID","New Resource Company E-mail"];
function parsePhone(s) {
let ss = s.replace(/[ \(\)\-+]/g, "");
return (ss.length == 10) ? "1" + ss : ss; // Adding US code
}
function parseDate(d) {
let dateRegEx = new RegExp(/<time datetime=\"([0-9]{4}-[0-9]{2}-[0-9]{2})\" ?\/>/);
return d.match(dateRegEx)[1];
}
function parseEmail(e) {
let s = e.replaceAll(/<.*?>|<\/.*?>/g, "");
let validEmailRegEx = new RegExp(/^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/);
const NON_VALID_EMAIL = "The input argument: '%s' is not a valid email";
if (!validEmailRegEx.test(s)) throw new Error(Utilities.formatString(NON_VALID_EMAIL, result));
return s;
}
let headers = { "Authorization": "Basic " + Utilities.base64Encode(USER + ':' + TOKEN) };
let params = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": false,
"contentType": "application/json"
};
let url = Utilities.formatString(URL, id);
let createResponse = UrlFetchApp.fetch(url, params);
let content = createResponse.getContentText();
let tableRegEx = new RegExp("<table.*?>(.*?)</table>");
let tableHtml = content.match(tableRegEx)[0];
let rowRegEx = new RegExp("<tr.*?>(.*?)</tr>", "g");
let rowsResult = tableHtml.match(rowRegEx);
let colRegExp = new RegExp("<td.*?>(.*?)</td>", "g");
let values = new Map();
rowsResult.forEach(function (item) { // parsing each column of given row
item = item.replace(/<p>|<\/p>|<p ?\/>/g, "").replace(/ /g, " ");
let row = [];
[...item.matchAll(colRegExp)].forEach(item => row.push(item[1])); // Getting the group (.*?)
row = row.filter(function (item) { return item != ""; }); // Keep non empty string only
let key = ROW_NAMES.find(it => it == row[0]);
if (key) {
if (row.length > 1) {
let records = row.slice(1);
if (key == ROW_NAMES[2]) { // phone number
records.forEach(function (item, index) {
this[index] = parsePhone(item);
}, records);
}
if ((key == ROW_NAMES[5]) || (key == ROW_NAMES[6])) {
records.forEach(function (item, index) {
this[index] = parseDate(item);
}, records);
}
if ((key == ROW_NAMES[3]) || (key == ROW_NAMES[10])) {
records.forEach(function (item, index) {
this[index] = parseEmail(item);
}, records);
}
values.set(key, records);
}
}
});
return values;
}
由于 Confluence 在我特定的板载 Confluence 模板上的格式,我正在为每一行解析特定值。
调用具有特定 Confluence ID 的函数:
let onboardValues = getOnboardRecords(<ID>);
console.log(JSON.stringify([...onboardValues.entries()]))
将为具有两个资源的入职模板生成以下输出:
[["First Name",["FirstName1","FirstName2"]],["Last Name",
["LastName1","LastName2"]],["Phone Number",["xxxxxxxxx","xxxxxxxxx"]],
["E-Mail",["xxxx@xxxx.xxx","xxxx.xxxxx@xxxxx.xxx"]],["Role",
["Delivery Manager","Sr. Developer"]],["Start Date",
["2021-11-01","2021-11-01"]],["End Date",["2021-11-30","2021-12-31"]],
["Vendor's Name",["xxxx","xxxxx"]],["Team",["xxxxxx]],
["New Resource ID",["xxxxxx","xxxxxx"]],
["New Resource Company E-mail",["xxxx@xxxxxx.xxx","xxxxxx@xxxx.xxx"]]]
我找到了一个类似的
我将上述问题的源代码改编如下:
function myFunction() {
const url = "https://<company>.atlassian.net/wiki/rest/api/content/<ID>";
const token = "<token>";
const user = "<email>";
headers = { "Authorization": "Basic " + Utilities.base64Encode(user + ':' + token) };
var params = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": false,
"contentType": "application/json"
};
let createResponse = UrlFetchApp.fetch(url, params);
console.log(createResponse.getContentText());
}
其中 <xxxx>
是与我的帐户相关的特定参数。 <ID>
是 Confluence 文档 ID。
我关注REST API specification for Confluence Cloud
我收到了回复,但它提供了有关该页面的一般信息属性。
将 url 更改为以下内容:
https://<company>.atlassian.net/wiki/rest/api/content/<ID>?expand=body.storage
添加以下后缀:?expand=body.storage
生成内容,但解析困难:
{"id":"2020706439","type":"page","status":"current","title":"Onboard Resource Template for
more than one resource","macroRenderedOutput":{},"body":{"storage":{"value":"<ac:structured-macro ac:name=
\"info\" ac:schema-version=\"1\" ac:macro-id=\"756d4d54-7492-49ac-b502-19d1a740ea92\"><ac:rich-text-body><p>
To use it, please make a copy of this template and replace the title with Resource Name(s) and add the
onboarding date as a suffix</p></ac:rich-text-body></ac:structured-macro><table data-layout=\"wide\">
<colgroup><col style=\"width: 182.0px;\" /><col style=\"width: 144.0px;\" /><col style=\"width: 148.0px;\" />
<col style=\"width: 143.0px;\" /><col style=\"width: 137.0px;\" /><col style=\"width: 142.0px;\" />
</colgroup><tbody><tr><td data-highlight-colour=\"#6fa8dc\" colspan=\"6\"><p style=\"text-align: center;\">
<strong>New Resource (s) Onboarding Information and Tracking</strong></p></td></tr>
<tr><td data-highlight-colour=\"#ff9900\"><p>Information Provided by Vendor</p></td>
<td data-highlight-colour=\"#ff9900\"><p>Resource 1</p></td><td data-highlight-colour=\"#ff9900\">
<p>Resource 2</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 3</p></td><td data-highlight-colour=\"#ff9900\">
<p>Resource 4</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 5</p></td></tr><tr><td><p>First
Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Last
Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Address</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Phone Number</p></td><td>
<p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>E-Mail</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>WFH or W@Office</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Location (if W@Office)</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Role</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Start Date</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>End Date</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Name</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Contact Name</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Phone Number</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Manager's Name</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Team</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#b6d7a8\" colspan=\"6\">
<p>Information Provided by Onboarding Manager</p></td></tr><tr><td><p>New Resource ID</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>New
Resource Company E-mail</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td></tr><tr><td><p>Cost Center</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Laptop Serial Number</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#b6d7a8\">
<p><ac:inline-comment-marker ac:ref=\"377a17e3-a869-451f-a58b-19cac76916a4\">Access Requests by
Rosana</ac:inline-comment-marker></p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">
Ticket Number</p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Date </p><p style=\"text-align: center;\">
Submitted</p></td><td data-highlight-colour=\"#b6d7a8\"><p>SNOW Assignee</p></td>
<td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">
Ready in<ac:inline-comment-marker ac:ref=\"269ae226-6036-4ede-9720-d3c25f5d31d2\"> </ac:inline-comment-marker>(n)-Days</p></td>
<td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Date Completed</p></td></tr><tr><td><p>Company ID Request</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Laptop</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td><p>Slack</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td>
<p>Outlook</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>WebEx</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Ping</p></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#a2c4c9\" colspan=\"6\"><p>Access Request by
Program Manager (or a PM on his behalf)</p></td></tr><tr><td><p>SNOW Access and Timesheets</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#f4cccc\" colspan=\"6\">
<p>Access Request/Action by David Leal</p></td></tr><tr><td><p>Access to Jira/Confluence</p></td>
<td><p /></td><td><p /></td><td><p>Jira Admin</p></td><td><p /></td><td><p /></td></tr>
<tr><td><p>Resource Plan</p></td><td><p /></td><td><p /></td><td><p>Snow Manager</p></td>
<td><p /></td><td><p /></td></tr>
<tr><td><p><em>Actions</em></p></td><td data-highlight-colour=\"#f4f5f7\" colspan=\"5\"><p style=\"text-align: center;\">
<em> Date Completed</em></p></td></tr><tr><td><p style=\"text-align: right;\">Add to Slack Channels</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr>
<td><p style=\"text-align: right;\">Add to JIRA Projects</p></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr>
<tr><td data-highlight-colour=\"#fff2cc\"><p>Access Requests by Tech Lead</p></td>
<td data-highlight-colour=\"#fff2cc\"><p>Ticket Number</p></td><td data-highlight-colour=\"#fff2cc\"><p>Date Submitted</p></td>
<td data-highlight-colour=\"#fff2cc\"><p>SNOW Assginee</p></td><td data-highlight-colour=\"#fff2cc\"><p>Ready in Days</p></td>
<td data-highlight-colour=\"#fff2cc\"><p>Date Completed</p></td></tr><tr><td><p>AWS Work Space (VDI)</p></td>
<td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>GitLab</p></td><td><p /></td><td><p /></td>
<td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>AWS Console</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td>
<td><p /></td></tr></tbody></table><p />",
"representation":"storage","embeddedContent":[],"_expandable":{"content":"/rest/api/content/2020706439"}},
"_expandable":{"editor":"","atlas_doc_format":"","view":"","export_view":"","styled_view":"","dynamic":"",
"editor2":"","anonymous_export_view":""}},"extensions":{"position":158},"_expandable":{"childTypes":"","container":
"/rest/api/space/PDC","metadata":"","operations":"","schedulePublishDate":"","children":"/rest/api/content/2020706439/child",
"restrictions":"/rest/api/content/2020706439/restriction/byOperation","history":"/rest/api/content/2020706439/history",
"ancestors":"","version":"","descendants":"/rest/api/content/2020706439/descendant","space":
"/rest/api/space/PDC"},"_links":{"editui":"/pages/resumedraft.action?draftId=2020706439","webui":
"/spaces/PDC/pages/2020706439/Onboard+Resource+Template+for+more+than+one+resource","context":"/wiki",
"self":"https://<company>.atlassian.net/wiki/rest/api/content/2020706439","tinyui":"/x/h4hxe","collection":
"/rest/api/content","base":"https://pan-american.atlassian.net/wiki"}}
我想获得的内容是合流 table 的一部分,如下所示:
关于这个问题,有以下问题:
- 这是获取 Confluence 页面内容以解析它的最佳方法吗?例如使用选项:
expand=body.storage
或者相反,有更好的方法来获取 Confluence 页面的内容(或特定的table),所以更容易解析。 - 如果得到的内容是最好的方法,那么有没有HTMLtablejavascript库或者工具或者脚本来解析table内容?
我相信你的目标如下。
- 您想从问题中的示例值 (
it generates the content, but it is difficult to parse:
) 中解析 HTML,并将它们放入 sheet。- 您已经能够从要使用的 API 中检索值。
在这种情况下,下面的示例脚本怎么样?在这种情况下,我想建议使用 Sheets API。 Sheets API 的 pasteData 可以解析 HTML table.
示例脚本:
请将以下脚本复制并粘贴到 Google Spreadsheet 的脚本编辑器中。而且,此脚本使用 Sheets API。所以please enable Sheets API at Advanced Google services。并且,请设置 sheet 名称。和 运行 功能。这样,Sheets API 解析 HTML table 并放入 sheet.
function myFunction() {
const obj = { "id": "2020706439", "type": "page", "status": "current", "title": "Onboard Resource Template for more than one resource", "macroRenderedOutput": {}, "body": { "storage": { "value": "<ac:structured-macro ac:name=\"info\" ac:schema-version=\"1\" ac:macro-id=\"756d4d54-7492-49ac-b502-19d1a740ea92\"><ac:rich-text-body><p>To use it, please make a copy of this template and replace the title with Resource Name(s) and add the onboarding date as a suffix</p></ac:rich-text-body></ac:structured-macro><table data-layout=\"wide\"><colgroup><col style=\"width: 182.0px;\" /><col style=\"width: 144.0px;\" /><col style=\"width: 148.0px;\" /><col style=\"width: 143.0px;\" /><col style=\"width: 137.0px;\" /><col style=\"width: 142.0px;\" /></colgroup><tbody><tr><td data-highlight-colour=\"#6fa8dc\" colspan=\"6\"><p style=\"text-align: center;\"><strong>New Resource (s) Onboarding Information and Tracking</strong></p></td></tr><tr><td data-highlight-colour=\"#ff9900\"><p>Information Provided by Vendor</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 1</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 2</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 3</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 4</p></td><td data-highlight-colour=\"#ff9900\"><p>Resource 5</p></td></tr><tr><td><p>First Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Last Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Address</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Phone Number</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>E-Mail</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>WFH or W@Office</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Location (if W@Office)</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Role</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Start Date</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>End Date</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Contact Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Vendor's Phone Number</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Manager's Name</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Team</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#b6d7a8\" colspan=\"6\"><p>Information Provided by Onboarding Manager</p></td></tr><tr><td><p>New Resource ID</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>New Resource Company E-mail</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Cost Center</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Laptop Serial Number</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#b6d7a8\"><p><ac:inline-comment-marker ac:ref=\"377a17e3-a869-451f-a58b-19cac76916a4\">Access Requests by Rosana</ac:inline-comment-marker></p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Ticket Number</p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Date </p><p style=\"text-align: center;\">Submitted</p></td><td data-highlight-colour=\"#b6d7a8\"><p>SNOW Assignee</p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Ready in<ac:inline-comment-marker ac:ref=\"269ae226-6036-4ede-9720-d3c25f5d31d2\"> </ac:inline-comment-marker>(n)-Days</p></td><td data-highlight-colour=\"#b6d7a8\"><p style=\"text-align: center;\">Date Completed</p></td></tr><tr><td><p>Company ID Request</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Laptop</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Slack</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Outlook</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>WebEx</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>Ping</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#a2c4c9\" colspan=\"6\"><p>Access Request by Program Manager (or a PM on his behalf)</p></td></tr><tr><td><p>SNOW Access and Timesheets</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#f4cccc\" colspan=\"6\"><p>Access Request/Action by David Leal</p></td></tr><tr><td><p>Access to Jira/Confluence</p></td><td><p /></td><td><p /></td><td><p>Jira Admin</p></td><td><p /></td><td><p /></td></tr><tr><td><p>Resource Plan</p></td><td><p /></td><td><p /></td><td><p>Snow Manager</p></td><td><p /></td><td><p /></td></tr><tr><td><p><em>Actions</em></p></td><td data-highlight-colour=\"#f4f5f7\" colspan=\"5\"><p style=\"text-align: center;\"><em> Date Completed</em></p></td></tr><tr><td><p style=\"text-align: right;\">Add to Slack Channels</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p style=\"text-align: right;\">Add to JIRA Projects</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td data-highlight-colour=\"#fff2cc\"><p>Access Requests by Tech Lead</p></td><td data-highlight-colour=\"#fff2cc\"><p>Ticket Number</p></td><td data-highlight-colour=\"#fff2cc\"><p>Date Submitted</p></td><td data-highlight-colour=\"#fff2cc\"><p>SNOW Assginee</p></td><td data-highlight-colour=\"#fff2cc\"><p>Ready in Days</p></td><td data-highlight-colour=\"#fff2cc\"><p>Date Completed</p></td></tr><tr><td><p>AWS Work Space (VDI)</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>GitLab</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr><tr><td><p>AWS Console</p></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td><td><p /></td></tr></tbody></table><p />", "representation": "storage", "embeddedContent": [], "_expandable": { "content": "/rest/api/content/2020706439" } }, "_expandable": { "editor": "", "atlas_doc_format": "", "view": "", "export_view": "", "styled_view": "", "dynamic": "", "editor2": "", "anonymous_export_view": "" } }, "extensions": { "position": 158 }, "_expandable": { "childTypes": "", "container": "/rest/api/space/PDC", "metadata": "", "operations": "", "schedulePublishDate": "", "children": "/rest/api/content/2020706439/child", "restrictions": "/rest/api/content/2020706439/restriction/byOperation", "history": "/rest/api/content/2020706439/history", "ancestors": "", "version": "", "descendants": "/rest/api/content/2020706439/descendant", "space": "/rest/api/space/PDC" }, "_links": { "editui": "/pages/resumedraft.action?draftId=2020706439", "webui": "/spaces/PDC/pages/2020706439/Onboard+Resource+Template+for+more+than+one+resource", "context": "/wiki", "self": "https://<company>.atlassian.net/wiki/rest/api/content/2020706439", "tinyui": "/x/h4hxe", "collection": "/rest/api/content", "base": "https://pan-american.atlassian.net/wiki" } };
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName("Sheet1"); // Please set the sheet name.
const requests = [{ pasteData: { data: obj.body.storage.value, html: true, coordinate: { sheetId: sheet.getSheetId() } } }];
Sheets.Spreadsheets.batchUpdate({requests}, ss.getId());
// When you want to retrieve the values as an array, please use the following script.
// const array = sheet.getDataRange().getValues();
// console.log(array)
}
结果:
当此脚本为运行时,得到如下结果
注:
- 此示例脚本使用您的示例值。因此,当值的结构发生变化时,此脚本可能无法使用。所以请注意这一点。
- 我可以确认当我使用你的样本值时这个脚本工作正常。所以当您测试此脚本的实际值时,当出现错误时,请再次检查检索到的值。
参考文献:
这里有一个可能的解决方案,使用正则表达式从 createResponse.getContentText()
中提取信息。它不如@Tanaike 提供的解决方案通用,但它不需要在活动 Spreadsheet 上生成辅助选项卡(sheet),在获取所有记录后需要将其删除:
/*
@param id {String} Confluence ID page
*/
function getOnboardRecords(id) {
const URL = https://<COMPANY>.atlassian.net/wiki/rest/api/content/%s?expand=body.storage;
const TOKEN = "Provide the token";
const USER = "Provide user name, i.e an email";
// Relevant columns to get the information
const ROW_NAMES = ["First Name", "Last Name", "Phone Number",
"E-Mail", "Role", "Start Date", "End Date", "Vendor's Name",
"Team", "New Resource ID","New Resource Company E-mail"];
function parsePhone(s) {
let ss = s.replace(/[ \(\)\-+]/g, "");
return (ss.length == 10) ? "1" + ss : ss; // Adding US code
}
function parseDate(d) {
let dateRegEx = new RegExp(/<time datetime=\"([0-9]{4}-[0-9]{2}-[0-9]{2})\" ?\/>/);
return d.match(dateRegEx)[1];
}
function parseEmail(e) {
let s = e.replaceAll(/<.*?>|<\/.*?>/g, "");
let validEmailRegEx = new RegExp(/^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/);
const NON_VALID_EMAIL = "The input argument: '%s' is not a valid email";
if (!validEmailRegEx.test(s)) throw new Error(Utilities.formatString(NON_VALID_EMAIL, result));
return s;
}
let headers = { "Authorization": "Basic " + Utilities.base64Encode(USER + ':' + TOKEN) };
let params = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": false,
"contentType": "application/json"
};
let url = Utilities.formatString(URL, id);
let createResponse = UrlFetchApp.fetch(url, params);
let content = createResponse.getContentText();
let tableRegEx = new RegExp("<table.*?>(.*?)</table>");
let tableHtml = content.match(tableRegEx)[0];
let rowRegEx = new RegExp("<tr.*?>(.*?)</tr>", "g");
let rowsResult = tableHtml.match(rowRegEx);
let colRegExp = new RegExp("<td.*?>(.*?)</td>", "g");
let values = new Map();
rowsResult.forEach(function (item) { // parsing each column of given row
item = item.replace(/<p>|<\/p>|<p ?\/>/g, "").replace(/ /g, " ");
let row = [];
[...item.matchAll(colRegExp)].forEach(item => row.push(item[1])); // Getting the group (.*?)
row = row.filter(function (item) { return item != ""; }); // Keep non empty string only
let key = ROW_NAMES.find(it => it == row[0]);
if (key) {
if (row.length > 1) {
let records = row.slice(1);
if (key == ROW_NAMES[2]) { // phone number
records.forEach(function (item, index) {
this[index] = parsePhone(item);
}, records);
}
if ((key == ROW_NAMES[5]) || (key == ROW_NAMES[6])) {
records.forEach(function (item, index) {
this[index] = parseDate(item);
}, records);
}
if ((key == ROW_NAMES[3]) || (key == ROW_NAMES[10])) {
records.forEach(function (item, index) {
this[index] = parseEmail(item);
}, records);
}
values.set(key, records);
}
}
});
return values;
}
由于 Confluence 在我特定的板载 Confluence 模板上的格式,我正在为每一行解析特定值。
调用具有特定 Confluence ID 的函数:
let onboardValues = getOnboardRecords(<ID>);
console.log(JSON.stringify([...onboardValues.entries()]))
将为具有两个资源的入职模板生成以下输出:
[["First Name",["FirstName1","FirstName2"]],["Last Name",
["LastName1","LastName2"]],["Phone Number",["xxxxxxxxx","xxxxxxxxx"]],
["E-Mail",["xxxx@xxxx.xxx","xxxx.xxxxx@xxxxx.xxx"]],["Role",
["Delivery Manager","Sr. Developer"]],["Start Date",
["2021-11-01","2021-11-01"]],["End Date",["2021-11-30","2021-12-31"]],
["Vendor's Name",["xxxx","xxxxx"]],["Team",["xxxxxx]],
["New Resource ID",["xxxxxx","xxxxxx"]],
["New Resource Company E-mail",["xxxx@xxxxxx.xxx","xxxxxx@xxxx.xxx"]]]