// Parse a WebDAV multistatus (PROPFIND) response into flat entries. // Pure ES5, no deps. Functions are TOP-LEVEL so the QML namespace import // exposes them directly (see Markdown.js): import "PropfindParser.js" as Prop // ... Prop.parse(xml, baseUrl) ... // The module.exports guard at the bottom is for node tests only. function decodePath(u) { try { return decodeURIComponent(u); } catch (e) { return u; } } function urlPath(u) { var m = /^[a-z]+:\/\/[^/]*(\/.*)$/i.exec(u); return m ? m[1] : u; } // entries: [{name, path, isDir, size, mtime}] sorted dirs-first, alpha. // path is relative to baseUrl, URL-decoded; dirs end with "/". function parse(xml, baseUrl) { var entries = []; if (!xml) return entries; var basePath = decodePath(urlPath(String(baseUrl || ""))); if (basePath.charAt(basePath.length - 1) === "/") { basePath = basePath.slice(0, -1); } var re = /<(?:[A-Za-z0-9_]+:)?response(?:\s[^>]*)?>([\s\S]*?)<\/(?:[A-Za-z0-9_]+:)?response>/gi; var blk; while ((blk = re.exec(xml)) !== null) { var body = blk[1]; var hrefMatch = /(?:[A-Za-z0-9_]+:)?href>([\s\S]*?)<\//.exec(body); if (!hrefMatch) continue; var href = hrefMatch[1].trim(); if (!href) continue; var decoded = decodePath(href); var rel = decoded; if (basePath && decoded.indexOf(basePath) === 0) { rel = decoded.substring(basePath.length); } if (rel.charAt(0) === "/") rel = rel.substring(1); if (rel === "" || rel === "/") continue; var isDir = rel.charAt(rel.length - 1) === "/"; var segs = rel.split("/"); var name = isDir ? segs[segs.length - 2] : segs[segs.length - 1]; if (!name) continue; var mtimeMatch = /(?:[A-Za-z0-9_]+:)?getlastmodified>([\s\S]*?)<\//.exec(body); var sizeMatch = /(?:[A-Za-z0-9_]+:)?getcontentlength>([\s\S]*?)<\//.exec(body); entries.push({ name: name, path: rel, isDir: isDir, size: sizeMatch ? parseInt(sizeMatch[1].trim(), 10) : 0, mtime: mtimeMatch ? mtimeMatch[1].trim() : "" }); } entries.sort(function (a, b) { if (a.isDir !== b.isDir) return a.isDir ? -1 : 1; var an = a.name.toLowerCase(); var bn = b.name.toLowerCase(); return an < bn ? -1 : (an > bn ? 1 : 0); }); return entries; } if (typeof module !== "undefined" && module.exports) { module.exports = { parse: parse }; }