// @require WFS_URL if (!WFS_URL) throw "Missing WFS_URL" var DBG = DBG || false var httpFetch = window.fetch // wfsFeature json format: /* { $fieldName: - string => field value - array of objects => ref features as objects (wfsFeature) - array of strings => ref features as xlink url } */ function p5WFS_ParseFeatureFieldRecurse(tagNode) { // @returns object from xml element var item = {} var i = 0 for (i = 0; i < tagNode.children.length; i++) { var fieldNode = tagNode.children[i] if ('p5:links' === fieldNode.tagName) { // // ​ // ​"https://.../wfs-data.php/default_db/?SERVICE=WFS&VERSION=1.0.0&TYPENAME=default_db__x3A__BI_audit_KW_requested_person:BI_audit_KW_requested_person&REQUEST=GetFeature&backRefNS=default_db/BI_audit_ENERGA_RUM_KONTRAHENCI_POWIAZANIA/BI_audit_ENERGA_RUM_KONTRAHENCI_POWIAZANIA&backRefPK=20&backRefField=default_db__x3A__BI_audit_KW_requested_person:BI_audit_KW_requested_person&startIndex=10" // ​ for (var j = 0; j < fieldNode.children.length; j++) { var p5LinkNode = fieldNode.children[j] if ('p5:next' === p5LinkNode.tagName) { var typeName = p5LinkNode.getAttribute('p5:typeName') item[ typeName ].push( { 'type': 'next', '@backRefNS': p5LinkNode.getAttribute('p5:backRefNS'), '@backRefPK': p5LinkNode.getAttribute('p5:backRefPK'), '@typeName': p5LinkNode.getAttribute('p5:typeName'), '@startIndex': p5LinkNode.getAttribute('p5:startIndex'), 'value': p5LinkNode.textContent } ) } else { if (DBG) console.warn("Not implemented p5:links/" + p5LinkNode.tagName) } } } else if (!fieldNode.children.length) { if (fieldNode.textContent) item[ fieldNode.localName ] = fieldNode.textContent else { var xlink = fieldNode.getAttribute('xlink:href') if (xlink) { if (!(fieldNode.tagName in item)) item[ fieldNode.tagName ] = [] item[ fieldNode.tagName ].push( xlink ) } } } else { if (!(fieldNode.tagName in item)) item[ fieldNode.tagName ] = [] item[ fieldNode.tagName ].push( p5WFS_ParseFeatureFieldRecurse(fieldNode) ) } } return item } function p5WFS_ParseFeatureMember(featureMember) { // @returns object from xml element if (!featureMember) return null if (!featureMember.children.length) return null var featureNode = featureMember.children[0] if (!featureNode) return null if (!featureNode.children.length) return null return p5WFS_ParseFeatureFieldRecurse(featureNode) } /** * @usage p5WFS_GetFeature('p5_default_db:CRM_PROCES', { 'featureID': 'CRM_PROCES.' + id, }).then(function (features) { // ... }).catch(function (e) { // ... }) * @usage - expected one feature p5WFS_GetFeature('p5_default_db:CRM_PROCES', { 'featureID': 'CRM_PROCES.' + id, }).then(function (features) { if (!features) throw "Nie odnaleziono rekordu id = " + id if (!features.length) throw "Nie odnaleziono rekordu id = " + id if (1 !== features.length) throw "Bład: API zwróciło za dużo rekordów" return features[0] console.log('fetched features', features) }).then(function (feature) { // ... }).catch(function (e) { // ... }) * @usage - POST p5WFS_GetFeature('p5_default_db:CRM_PROCES', { // 'Filter': '' + "PARENT_ID" + '' + parent_id + '', 'sortBy': 'SORT_PRIO+A,ID', 'ogc:Filter': '' + '' + '' + "PARENT_ID" + '' + parent_id + '' + '' + '' }).then(function (features) { ... */ function p5WFS_GetFeature(typeName, query) { // @returns Promise var postData = null var link = WFS_URL + '?SERVICE=WFS&VERSION=1.0.0' + '&REQUEST=GetFeature' + '&TYPENAME=' + typeName + '&SRSNAME=EPSG:3003' ; if ('WFS_URL' in query && query['WFS_URL'].length) { link = query['WFS_URL'] link += ( (-1 !== query['WFS_URL'].indexOf('?')) ? '&' : '?' ) link += 'SERVICE=WFS&VERSION=1.0.0' link += '&REQUEST=GetFeature' link += '&TYPENAME=' + typeName link += '&SRSNAME=EPSG:3003' } // '&Filter=ID' + id + '' var query = query || {} if ('featureID' in query) link += '&featureID=' + query['featureID'] if ('Filter' in query && 'string' === typeof query['Filter']) { var ogcFilter = ('' !== query['Filter'].substr(0, ''.length)) ? '' + query['Filter'] + '' : query['Filter'] ; link += '&Filter=' + ogcFilter } if ('ogc:Filter' in query && 'string' === typeof query['ogc:Filter']) { var headerOgcFilter = '' if ('' === query['ogc:Filter'].substr(0, ''.length)) { postData = headerOgcFilter + '' + query['ogc:Filter'] + '' + '' } else if ('' === query['ogc:Filter'].substr(0, ''.length)) { postData = headerOgcFilter + query['ogc:Filter'] + '' } else { return Promise.reject(new Error('Wrong syntax ogc:Filter')) } } if ('graphql:query' in query && 'string' === typeof query['graphql:query']) { // TODO: http://graphql.org/learn/queries/ link += '&outputFormat=json' postData = query['graphql:query'] } if ('sortBy' in query) link += '&sortBy=' + query['sortBy'] if ('maxFeatures' in query) link += '&maxFeatures=' + query['maxFeatures'] if ('count' in query) link += '&count=' + query['count'] if ('startIndex' in query) link += '&startIndex=' + query['startIndex'] if ('primaryKey' in query) link += '&primaryKey=' + query['primaryKey'] if ('resolveDepth' in query && !('resolve' in query)) return Promise.reject(new Error('ResolveDepth set but missing resolve="all"')) if ('resolve' in query) link += '&resolve=' + query['resolve'] if ('resolveDepth' in query) link += '&resolveDepth=' + query['resolveDepth'] if ('xlink' in query) link += '&xlink=' + query['xlink'] // NOTE: replace '#' to '/' if ('root' in query) link += '&root=' + query['root'] // NOTE: require admin perms (admin level 0) if ('backRefNS' in query && 'backRefPK' in query && 'backRefField' in query) { link += '&backRefNS=' + query['backRefNS'] link += '&backRefPK=' + query['backRefPK'] link += '&backRefField=' + query['backRefField'] } if ('p5:next' in query) link = query['p5:next']; var method = (postData) ? 'POST' : 'GET' var wfsPromise = httpFetch(link, Object.assign({ method: method, credentials: 'include', }, ('POST' === method) ? { body: postData } : {} )).then(function (response) { return response.text() }); return _p5WFS_GetFeaturePromise(wfsPromise); } function p5WFS_GetFeatureFromXml(url) { var wfsPromise = httpFetch(url, { method: 'GET', credentials: 'include', }).then(function (response) { return response.text() }); return _p5WFS_GetFeaturePromise(wfsPromise); } function p5WFS_GetFeatureFromXmlString(xmlString) { var wfsPromise = new Promise(function (resolve, reject) { resolve(xmlString); }); return _p5WFS_GetFeaturePromise(wfsPromise); } function _p5WFS_GetFeaturePromise(wfsPromise) { return wfsPromise.then(function (responseText) { return (new DOMParser()).parseFromString(responseText, "text/xml"); }).then(function (xmlResponse) { if (!xmlResponse.children.length) throw "Missing response xml root element" return xmlResponse.children[0] }).then(function (xmlRoot) { if ('html' === xmlRoot.localName) { // console.log(xmlRoot) // html / body / parseerror / div throw "Parse xml error" } if ('FeatureCollection' !== xmlRoot.localName) { if ('ServiceExceptionReport' === xmlRoot.tagName) { if (xmlRoot.children[0] && xmlRoot.children[0].textContent) throw xmlRoot.children[0].textContent throw "WFS API Exception" } throw "Missing FeatureCollection as root element in wfs response" } var features = [] for (var i = 0; i < xmlRoot.children.length; i++) { features.push(p5WFS_ParseFeatureMember(xmlRoot.children[i])) } return features.filter(function (item) { return !!item; }) }) } module.exports = { p5WFS_ParseFeatureMember: p5WFS_ParseFeatureMember, p5WFS_ParseFeatureFieldRecurse: p5WFS_ParseFeatureFieldRecurse, p5WFS_GetFeature: p5WFS_GetFeature, p5WFS_GetFeatureFromXml: p5WFS_GetFeatureFromXml, p5WFS_GetFeatureFromXmlString: p5WFS_GetFeatureFromXmlString, }