diff --git a/client/components/Search/BaseList.js b/client/components/Search/BaseList.js index a9fc857..ad259bb 100644 --- a/client/components/Search/BaseList.js +++ b/client/components/Search/BaseList.js @@ -1,4 +1,4 @@ -import moment from 'moment'; +import dayjs from 'dayjs'; import _ from 'lodash'; import authorBooksStorage from './authorBooksStorage'; @@ -467,13 +467,13 @@ export default class BaseList { */ const sqlFormat = 'YYYY-MM-DD'; switch (date) { - case 'today': date = utils.dateFormat(moment(), sqlFormat); break; - case '3days': date = utils.dateFormat(moment().subtract(3, 'days'), sqlFormat); break; - case 'week': date = utils.dateFormat(moment().subtract(1, 'weeks'), sqlFormat); break; - case '2weeks': date = utils.dateFormat(moment().subtract(2, 'weeks'), sqlFormat); break; - case 'month': date = utils.dateFormat(moment().subtract(1, 'months'), sqlFormat); break; - case '2months': date = utils.dateFormat(moment().subtract(2, 'months'), sqlFormat); break; - case '3months': date = utils.dateFormat(moment().subtract(3, 'months'), sqlFormat); break; + case 'today': date = utils.dateFormat(dayjs(), sqlFormat); break; + case '3days': date = utils.dateFormat(dayjs().subtract(3, 'days'), sqlFormat); break; + case 'week': date = utils.dateFormat(dayjs().subtract(1, 'weeks'), sqlFormat); break; + case '2weeks': date = utils.dateFormat(dayjs().subtract(2, 'weeks'), sqlFormat); break; + case 'month': date = utils.dateFormat(dayjs().subtract(1, 'months'), sqlFormat); break; + case '2months': date = utils.dateFormat(dayjs().subtract(2, 'months'), sqlFormat); break; + case '3months': date = utils.dateFormat(dayjs().subtract(3, 'months'), sqlFormat); break; default: date = ''; } diff --git a/client/components/Search/BookInfoDialog/BookInfoDialog.vue b/client/components/Search/BookInfoDialog/BookInfoDialog.vue index b7bed34..36b5863 100644 --- a/client/components/Search/BookInfoDialog/BookInfoDialog.vue +++ b/client/components/Search/BookInfoDialog/BookInfoDialog.vue @@ -185,7 +185,7 @@ class BookInfoDialog { return utils.sqlDateFormat(value); if (nodePath == 'fileInfo/del') - return (value ? 'Да' : 'Нет'); + return (value ? 'Да' : ''); if (nodePath == 'titleInfo/author') return value.split(',').join(', '); @@ -239,7 +239,6 @@ class BookInfoDialog { parseBookInfo() { const bookInfo = this.bookInfo; - const parser = new Fb2Parser(); //cover if (bookInfo.cover) @@ -247,16 +246,10 @@ class BookInfoDialog { //fb2 if (bookInfo.fb2) { - this.fb2 = parser.bookInfoList(bookInfo.fb2, { - valueToString(value, nodePath, origVTS) {//eslint-disable-line no-unused-vars - if (nodePath == 'documentInfo/historyHtml' && value) - return value.replace(/

/g, `

`); + const parser = new Fb2Parser(bookInfo.fb2); + + const infoObj = parser.bookInfo(); - return origVTS(value, nodePath); - }, - }); - - const infoObj = parser.bookInfo(bookInfo.fb2); if (infoObj.titleInfo) { let ann = infoObj.titleInfo.annotationHtml; if (ann) { @@ -264,6 +257,15 @@ class BookInfoDialog { this.annotation = ann; } } + + this.fb2 = parser.bookInfoList(infoObj, { + valueToString(value, nodePath, origVTS) {//eslint-disable-line no-unused-vars + if (nodePath == 'documentInfo/historyHtml' && value) + return value.replace(/

/g, `

`); + + return origVTS(value, nodePath); + }, + }); } //book diff --git a/client/components/Search/BookView/BookView.vue b/client/components/Search/BookView/BookView.vue index 688d656..cb9b9db 100644 --- a/client/components/Search/BookView/BookView.vue +++ b/client/components/Search/BookView/BookView.vue @@ -55,8 +55,8 @@ {{ bookSize }}, {{ book.ext }} -

- [ . . . ] +
+ (инфо)
diff --git a/client/components/Search/Search.vue b/client/components/Search/Search.vue index a07514d..3ac28b4 100644 --- a/client/components/Search/Search.vue +++ b/client/components/Search/Search.vue @@ -204,7 +204,7 @@
-
+
{{ projectName }}
@@ -232,7 +232,7 @@ - + diff --git a/client/share/utils.js b/client/share/utils.js index 573cb6f..3607954 100644 --- a/client/share/utils.js +++ b/client/share/utils.js @@ -1,4 +1,4 @@ -import moment from 'moment'; +import dayjs from 'dayjs'; import {Buffer} from 'safe-buffer'; //import _ from 'lodash'; @@ -121,11 +121,11 @@ export function isDigit(c) { } export function dateFormat(date, format = 'DD.MM.YYYY') { - return moment(date).format(format); + return dayjs(date).format(format); } export function sqlDateFormat(date, format = 'DD.MM.YYYY') { - return moment(date, 'YYYY-MM-DD').format(format); + return dayjs(date, 'YYYY-MM-DD').format(format); } export function isManualDate(date) { diff --git a/package-lock.json b/package-lock.json index d61ac87..19fa89d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,19 @@ { "name": "inpx-web", - "version": "1.2.0", + "version": "1.2.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "inpx-web", - "version": "1.2.0", + "version": "1.2.1", "hasInstallScript": true, "license": "CC0-1.0", "dependencies": { "@quasar/extras": "^1.15.0", "axios": "^0.27.2", "chardet": "^1.5.0", + "dayjs": "^1.11.6", "express": "^4.18.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.3", @@ -20,7 +21,6 @@ "localforage": "^1.10.0", "lodash": "^4.17.21", "minimist": "^1.2.6", - "moment": "^2.29.4", "node-stream-zip": "^1.15.0", "quasar": "^2.7.5", "safe-buffer": "^5.2.1", @@ -3433,6 +3433,11 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" }, + "node_modules/dayjs": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -5519,14 +5524,6 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "engines": { - "node": "*" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -11324,6 +11321,11 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" }, + "dayjs": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -12879,11 +12881,6 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, - "moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/package.json b/package.json index 5015b26..885c135 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "inpx-web", - "version": "1.2.0", + "version": "1.2.1", "author": "Book Pauk ", "license": "CC0-1.0", "repository": "bookpauk/inpx-web", @@ -52,6 +52,7 @@ "@quasar/extras": "^1.15.0", "axios": "^0.27.2", "chardet": "^1.5.0", + "dayjs": "^1.11.6", "express": "^4.18.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.3", @@ -59,7 +60,6 @@ "localforage": "^1.10.0", "lodash": "^4.17.21", "minimist": "^1.2.6", - "moment": "^2.29.4", "node-stream-zip": "^1.15.0", "quasar": "^2.7.5", "safe-buffer": "^5.2.1", diff --git a/server/core/WebWorker.js b/server/core/WebWorker.js index c862b0d..b1d715c 100644 --- a/server/core/WebWorker.js +++ b/server/core/WebWorker.js @@ -369,7 +369,7 @@ class WebWorker { const link = `${this.config.filesPathStatic}/${hash}`; const bookFile = `${this.config.filesDir}/${hash}`; - const bookFileDesc = `${bookFile}.json`; + const bookFileDesc = `${bookFile}.d.json`; if (!await fs.pathExists(bookFile) || !await fs.pathExists(bookFileDesc)) { if (!await fs.pathExists(bookFile) && extractedFile) { @@ -435,7 +435,7 @@ class WebWorker { if (rows.length) {//хеш найден по bookPath const hash = rows[0].hash; const bookFile = `${this.config.filesDir}/${hash}`; - const bookFileDesc = `${bookFile}.json`; + const bookFileDesc = `${bookFile}.d.json`; if (await fs.pathExists(bookFile) && await fs.pathExists(bookFileDesc)) { link = `${this.config.filesPathStatic}/${hash}`; @@ -467,9 +467,9 @@ class WebWorker { let bookInfo = await this.getBookLink(bookId); const hash = path.basename(bookInfo.link); const bookFile = `${this.config.filesDir}/${hash}`; - const bookFileInfo = `${bookFile}.info`; + const bookFileInfo = `${bookFile}.i.json`; - const restoreBookInfo = async() => { + const restoreBookInfo = async(info) => { const result = {}; const rows = await db.select({table: 'book', where: `@@id(${db.esc(bookId)})`}); @@ -478,10 +478,12 @@ class WebWorker { result.book = book; result.cover = ''; result.fb2 = false; + let parser = null; if (book.ext == 'fb2') { const {fb2, cover, coverExt} = await this.fb2Helper.getDescAndCover(bookFile); - result.fb2 = fb2; + parser = fb2; + result.fb2 = fb2.rawNodes; if (cover) { result.cover = `${this.config.filesPathStatic}/${hash}${coverExt}`; @@ -489,12 +491,16 @@ class WebWorker { } } - return result; + Object.assign(info ,result); + await fs.writeFile(bookFileInfo, JSON.stringify(info)); + + if (this.config.branch === 'development') { + await fs.writeFile(`${bookFile}.dev`, `${JSON.stringify(info, null, 2)}\n\n${parser ? parser.toString({format: true}) : ''}`); + } }; if (!await fs.pathExists(bookFileInfo)) { - Object.assign(bookInfo, await restoreBookInfo()); - await fs.writeFile(bookFileInfo, JSON.stringify(bookInfo, null, 2)); + await restoreBookInfo(bookInfo); } else { await utils.touchFile(bookFileInfo); const info = await fs.readFile(bookFileInfo, 'utf-8'); @@ -506,8 +512,7 @@ class WebWorker { coverFile = `${this.config.publicFilesDir}${tmpInfo.cover}`; if (coverFile && !await fs.pathExists(coverFile)) { - Object.assign(bookInfo, await restoreBookInfo()); - await fs.writeFile(bookFileInfo, JSON.stringify(bookInfo, null, 2)); + await restoreBookInfo(bookInfo); } else { bookInfo = tmpInfo; } diff --git a/server/core/fb2/Fb2Helper.js b/server/core/fb2/Fb2Helper.js index e70e30d..5a3383b 100644 --- a/server/core/fb2/Fb2Helper.js +++ b/server/core/fb2/Fb2Helper.js @@ -63,12 +63,11 @@ class Fb2Helper { pickNode: route => route.indexOf('fictionbook/body') !== 0, }); - const desc = parser.$$('description').toObject(); - const coverImage = parser.inspector(desc).$('description/title-info/coverpage/image'); + const coverImage = parser.$$('/description/title-info/coverpage/image'); let cover = null; let coverExt = ''; - if (coverImage) { + if (coverImage.count) { const coverAttrs = coverImage.attrs(); const href = coverAttrs[`${parser.xlinkNS}:href`]; let coverType = coverAttrs['content-type']; @@ -79,24 +78,21 @@ class Fb2Helper { const binaryId = (href[0] == '#' ? href.substring(1) : href); //найдем нужный image - parser.$$('binary').eachSelf(node => { + for (const node of parser.$$array('/binary')) { let attrs = node.attrs(); if (!attrs) return; - attrs = Object.fromEntries(attrs); if (attrs.id === binaryId) { - const textNode = new Fb2Parser(node.value); - const base64 = textNode.$self('*TEXT').value; - + const base64 = node.text(); cover = (base64 ? Buffer.from(base64, 'base64') : null); } - }); + } } } parser.remove('binary'); - return {fb2: parser.toObject(), cover, coverExt}; + return {fb2: parser, cover, coverExt}; } } diff --git a/server/core/fb2/Fb2Parser.js b/server/core/fb2/Fb2Parser.js index 70e2815..4a23075 100644 --- a/server/core/fb2/Fb2Parser.js +++ b/server/core/fb2/Fb2Parser.js @@ -3,7 +3,7 @@ const XmlParser = require('../xml/XmlParser'); class Fb2Parser extends XmlParser { get xlinkNS() { if (!this._xlinkNS) { - const rootAttrs = this.$self().attrs(); + const rootAttrs = this.selectFirstSelf().attrs(); let ns = 'l'; for (const [key, value] of rootAttrs) { if (value == 'http://www.w3.org/1999/xlink') { @@ -18,27 +18,24 @@ class Fb2Parser extends XmlParser { return this._xlinkNS; } - bookInfo(fb2Object) { + bookInfo() { const result = {}; - if (!fb2Object) - fb2Object = this.toObject(); - - const desc = this.inspector(fb2Object).$('fictionbook/description'); + const desc = this.$$('/description/'); if (!desc) return result; const parseAuthors = (node, tagName) => { const authors = []; - for (const a of node.$$(tagName)) { + for (const a of node.$$array(tagName)) { let names = []; - names.push(a.text('last-name')); - names.push(a.text('first-name')); - names.push(a.text('middle-name')); + names.push(a.text('/last-name')); + names.push(a.text('/first-name')); + names.push(a.text('/middle-name')); names = names.filter(n => n); if (!names.length) - names.push(a.text('nickname')); + names.push(a.text('/nickname')); authors.push(names.join(' ')); } @@ -48,7 +45,7 @@ class Fb2Parser extends XmlParser { const parseSequence = (node, tagName) => { const sequence = []; - for (const s of node.$$(tagName)) { + for (const s of node.$$array(tagName)) { const seqAttrs = s.attrs() || {}; const name = seqAttrs['name'] || null; const num = seqAttrs['number'] || null; @@ -64,7 +61,7 @@ class Fb2Parser extends XmlParser { const info = {}; info.genre = []; - for (const g of titleInfo.$$('genre')) + for (const g of titleInfo.$$array('genre')) info.genre.push(g.text()); info.author = parseAuthors(titleInfo, 'author'); @@ -77,7 +74,7 @@ class Fb2Parser extends XmlParser { info.annotationHtml = null; if (info.annotation) { //annotation как кусок xml - info.annotationXml = (new XmlParser()).fromObject(info.annotation).toString({noHeader: true}); + info.annotationXml = titleInfo.$$('annotation/').toString({noHeader: true}); //annotation как html info.annotationHtml = this.toHtml(info.annotationXml); @@ -97,19 +94,19 @@ class Fb2Parser extends XmlParser { } //title-info - const titleInfo = desc.$('title-info'); + const titleInfo = desc.$$('title-info/'); if (titleInfo) { result.titleInfo = parseTitleInfo(titleInfo); } //src-title-info - const srcTitleInfo = desc.$('src-title-info'); + const srcTitleInfo = desc.$$('src-title-info/'); if (srcTitleInfo) { result.srcTitleInfo = parseTitleInfo(srcTitleInfo); } //document-info - const documentInfo = desc.$('document-info'); + const documentInfo = desc.$$('document-info/'); if (documentInfo) { const info = {}; @@ -118,7 +115,7 @@ class Fb2Parser extends XmlParser { info.date = documentInfo.text('date'); info.srcUrl = []; - for (const url of documentInfo.$$('src-url')) + for (const url of documentInfo.$$array('src-url')) info.srcUrl.push(url.text()); info.srcOcr = documentInfo.text('src-ocr'); @@ -131,7 +128,7 @@ class Fb2Parser extends XmlParser { info.historyHtml = null; if (info.history) { //history как кусок xml - info.historyXml = (new XmlParser()).fromObject(info.history).toString({noHeader: true}); + info.historyXml = documentInfo.$$('history/').toString({noHeader: true}); //history как html info.historyHtml = this.toHtml(info.historyXml); @@ -143,7 +140,7 @@ class Fb2Parser extends XmlParser { } //publish-info - const publishInfo = desc.$('publish-info'); + const publishInfo = desc.$$('publish-info/'); if (publishInfo) { const info = {}; @@ -160,7 +157,7 @@ class Fb2Parser extends XmlParser { return result; } - bookInfoList(fb2Object, options = {}) { + bookInfoList(bookInfo, options = {}) { let { correctMapping = false, valueToString = false, @@ -236,7 +233,7 @@ class Fb2Parser extends XmlParser { ]; mapping = correctMapping(mapping); - const bookInfo = this.bookInfo(fb2Object); + bookInfo = (bookInfo ? bookInfo : this.bookInfo()); //заполняем mapping let result = []; diff --git a/server/core/xml/ObjectInspector.js b/server/core/xml/ObjectInspector.js index 0adc188..21cf747 100644 --- a/server/core/xml/ObjectInspector.js +++ b/server/core/xml/ObjectInspector.js @@ -3,7 +3,7 @@ class ObjectInspector { this.raw = raw; } - makeSelector(selector) { + narrowSelector(selector) { const result = []; selector = selector.trim(); @@ -31,7 +31,7 @@ class ObjectInspector { } select(selector = '') { - selector = this.makeSelector(selector); + selector = this.narrowSelector(selector); let raw = this.raw; for (const s of selector) { @@ -50,14 +50,10 @@ class ObjectInspector { } if (raw === undefined || raw === null) { - raw = null; - break; + return []; } } - if (raw === null) - return []; - raw = (Array.isArray(raw) ? raw : [raw]); const result = []; diff --git a/server/core/xml/XmlParser.js b/server/core/xml/XmlParser.js index 26da7e7..2c073c6 100644 --- a/server/core/xml/XmlParser.js +++ b/server/core/xml/XmlParser.js @@ -1,5 +1,4 @@ const sax = require('./sax'); -const ObjectInspector = require('./ObjectInspector'); //node types const NODE = 1; @@ -22,7 +21,7 @@ const type2name = { }; class NodeBase { - makeSelectorObj(selectorString) { + wideSelector(selectorString) { const result = {all: false, before: false, type: 0, name: ''}; if (selectorString === '') { @@ -153,7 +152,7 @@ class NodeObject extends NodeBase { if (this.type !== NODE) return; - const selectorObj = this.makeSelectorObj(after); + const selectorObj = this.wideSelector(after); if (!Array.isArray(this.raw[3])) this.raw[3] = []; @@ -172,7 +171,7 @@ class NodeObject extends NodeBase { if (this.type !== NODE || !this.raw[3]) return; - const selectorObj = this.makeSelectorObj(selector); + const selectorObj = this.wideSelector(selector); this.rawRemove(this.raw[3], selectorObj); if (!this.raw[3].length) @@ -233,6 +232,14 @@ class XmlParser extends NodeBase { return this.rawNodes.length; } + get nodes() { + const result = []; + for (const n of this.rawNodes) + result.push(new NodeObject(n)); + + return result; + } + nodeObject(node) { return new NodeObject(node); } @@ -279,7 +286,7 @@ class XmlParser extends NodeBase { } add(node, after = '*') { - const selectorObj = this.makeSelectorObj(after); + const selectorObj = this.wideSelector(after); for (const n of this.rawNodes) { if (n && n[0] === NODE) { @@ -299,7 +306,7 @@ class XmlParser extends NodeBase { } addRoot(node, after = '*') { - const selectorObj = this.makeSelectorObj(after); + const selectorObj = this.wideSelector(after); if (Array.isArray(node)) { for (const node_ of node) @@ -312,7 +319,7 @@ class XmlParser extends NodeBase { } remove(selector = '') { - const selectorObj = this.makeSelectorObj(selector); + const selectorObj = this.wideSelector(selector); for (const n of this.rawNodes) { if (n && n[0] === NODE && Array.isArray(n[3])) { @@ -326,7 +333,7 @@ class XmlParser extends NodeBase { } removeRoot(selector = '') { - const selectorObj = this.makeSelectorObj(selector); + const selectorObj = this.wideSelector(selector); this.rawRemove(this.rawNodes, selectorObj); @@ -409,7 +416,7 @@ class XmlParser extends NodeBase { newRawNodes = res.rawNodes; } else { - const selectorObj = this.makeSelectorObj(selector); + const selectorObj = this.wideSelector(selector); if (self) { this.rawSelect(this.rawNodes, selectorObj, (node) => { @@ -429,11 +436,7 @@ class XmlParser extends NodeBase { return new XmlParser(newRawNodes); } - $$(selector, self) { - return this.select(selector, self); - } - - $$self(selector) { + selectSelf(selector) { return this.select(selector, true); } @@ -443,11 +446,7 @@ class XmlParser extends NodeBase { return new NodeObject(node); } - $(selector, self) { - return this.selectFirst(selector, self); - } - - $self(selector) { + selectFirstSelf(selector) { return this.selectFirst(selector, true); } @@ -760,12 +759,138 @@ class XmlParser extends NodeBase { return this; } - inspector(obj) { - if (!obj) - obj = this.toObject(); + // XML Inspector start + narrowSelector(selector) { + const result = []; + selector = selector.trim(); + + //последний индекс не учитывется, только если не задан явно + if (selector && selector[selector.length - 1] == ']') + selector += '/'; - return new ObjectInspector(obj); + const levels = selector.split('/'); + + for (const level of levels) { + const [name, indexPart] = level.split('['); + let index = 0; + if (indexPart) { + const i = indexPart.indexOf(']'); + index = parseInt(indexPart.substring(0, i), 10) || 0; + } + + let type = NODE; + if (name[0] === '*') { + const typeName = name.substring(1); + type = name2type[typeName]; + if (!type) + throw new Error(`Unknown selector type: ${typeName}`); + } + + result.push({type, name, index}); + } + + if (result.length); + result[result.length - 1].last = true; + + return result; } + + inspect(selector = '') { + selector = this.narrowSelector(selector); + + let raw = this.rawNodes; + for (const s of selector) { + if (s.name) { + let found = []; + for (const n of raw) { + if (n[0] === s.type && (n[0] !== NODE || s.name === '*NODE' || n[1] === s.name)) { + found.push(n); + + if (found.length > s.index && !s.last) + break; + } + } + + raw = found; + } + + if (raw.length && !s.last) { + if (s.index < raw.length) { + raw = raw[s.index]; + if (raw[0] === NODE && raw[3]) + raw = raw[3]; + else { + raw = []; + break; + } + } else { + raw = []; + break; + } + } + } + + return new XmlParser(raw); + } + + $$(selector) { + return this.inspect(selector); + } + + $$array(selector) { + const res = this.inspect(selector); + const result = []; + for (const n of res.rawNodes) + if (n[0] === NODE) + result.push(new XmlParser([n])); + + return result; + } + + $(selector) { + const res = this.inspect(selector); + const node = (res.count ? res.rawNodes[0] : null); + return new NodeObject(node); + } + + v(selector = '') { + const res = this.$(selector); + return (res.type ? res.value : null); + } + + text(selector = '') { + const res = this.$(`${selector}/*TEXT`); + return (res.type === TEXT ? res.value : null); + } + + comment(selector = '') { + const res = this.$(`${selector}/*COMMENT`); + return (res.type === COMMENT ? res.value : null); + } + + cdata(selector = '') { + const res = this.$(`${selector}/*CDATA`); + return (res.type === CDATA ? res.value : null); + } + + concat(selector = '') { + const res = this.$$(selector); + const out = []; + for (const n of res.rawNodes) { + const node = new NodeObject(n); + if (node.type && node.type !== NODE) + out.push(node.value); + } + + return (out.length ? out.join('') : null); + } + + attrs(selector = '') { + const res = this.$(selector); + const attrs = res.attrs(); + return (res.type === NODE && attrs ? Object.fromEntries(attrs) : null); + } + // XML Inspector finish } module.exports = XmlParser; \ No newline at end of file diff --git a/server/index.js b/server/index.js index 15e387f..9e2e8aa 100644 --- a/server/index.js +++ b/server/index.js @@ -191,7 +191,7 @@ function initStatic(app, config) { if (path.extname(req.path) == '') { const bookFile = `${config.publicFilesDir}${req.path}`; - const bookFileDesc = `${bookFile}.json`; + const bookFileDesc = `${bookFile}.d.json`; let downFileName = ''; //восстановим из json-файла описания