Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xmlfeedparser.js 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. const stream_1 = require("stream");
  7. const sax_1 = __importDefault(require("sax"));
  8. /**
  9. * If this object has text, and there is no other children,
  10. * or the only other key is type, make the object the text.
  11. *
  12. * @param {Object} obj
  13. * @returns {Object}
  14. */
  15. const cleanObj = (obj) => {
  16. let keys = Object.keys(obj).length;
  17. if (obj.text != null) {
  18. // If this tag has text, trim it.
  19. obj.text = trimIndent(obj.text);
  20. if (keys === 1 || (keys === 2 && obj.type != null)) {
  21. return obj.text;
  22. }
  23. }
  24. else if (keys === 0) {
  25. return '';
  26. }
  27. return obj;
  28. };
  29. /**
  30. * Trims the indent from text that sax-js emits. Some xml feeds will
  31. * add indent to multiline text. Example:
  32. *
  33. * <item>
  34. * The big brown fox
  35. * jumped over the lazy dog
  36. * </item>
  37. *
  38. * @param {string} str
  39. * @returns {string}
  40. */
  41. const trimIndent = (str) => {
  42. let split = str.split('\n'), rs;
  43. // The last line should be indented and only contain whitespace.
  44. if (split.length > 1 &&
  45. (rs = /^((?: {3})+|(?: {2})+|(?: {4})+|(?:\t)+)$/m.exec(split[split.length - 1]))) {
  46. // The very first line should be empty.
  47. if (split.shift() !== '') {
  48. return str;
  49. }
  50. // Remove the last line, as it's only whitespace.
  51. split.pop();
  52. let wholeindent = rs[0] + rs[1];
  53. // Remove indent from beginning of every line.
  54. for (let i = 0, l = split.length; i < l; i++) {
  55. let s = split[i];
  56. if (s.indexOf(wholeindent) !== 0) {
  57. return str;
  58. }
  59. split[i] = s.substr(wholeindent.length);
  60. }
  61. str = split.join('\n');
  62. }
  63. return str;
  64. };
  65. /**
  66. * Parses an RSS/Atom feed.
  67. *
  68. * @param {boolean} buffer If true, will buffer entire object.
  69. * @return {sax.Stream}
  70. */
  71. class XMLFeedParser extends stream_1.Writable {
  72. constructor(buffer) {
  73. super();
  74. this._buffer = buffer;
  75. const parser = this.parser = sax_1.default.createStream(false, { lowercase: true });
  76. const stack = [];
  77. this._root = this._obj = {};
  78. // First start listening for the root tag.
  79. const openf1 = (node) => {
  80. if (node.name === 'channel' || node.name === 'feed') {
  81. if (node.name === 'feed') {
  82. let type = 'atom';
  83. this._root.type = type;
  84. parser.emit('type', type);
  85. }
  86. parser.removeListener('opentag', openf1);
  87. parser.on('text', ontext);
  88. parser.on('cdata', ontext);
  89. parser.on('opentag', onopentag);
  90. parser.on('closetag', onclosetag);
  91. }
  92. else if (node.name === 'rss' || node.name === 'rdf:rdf') {
  93. let type = 'rss ' + (node.attributes.version || '1.0');
  94. this._root.type = type;
  95. parser.emit('type', type);
  96. }
  97. else {
  98. parser.removeListener('opentag', openf1);
  99. parser.emit('error', new Error('Feed type not recognized'));
  100. // parser.closed = true;
  101. }
  102. };
  103. parser.on('opentag', openf1);
  104. const ontext = (text) => {
  105. // Make sure text events are text and not just whitespace.
  106. const rs = /\n(( {3})+|( {2})+|( {4})+|(\t)+)$/m.exec(text);
  107. if (rs !== null && rs.index === 0 && rs[0] === rs.input) {
  108. return;
  109. }
  110. const obj = this._obj;
  111. if (obj.text == null) {
  112. obj.text = '';
  113. }
  114. obj.text += text;
  115. };
  116. // After the root is found, start storing the rest of the document.
  117. const onopentag = (node) => {
  118. const key = node.name;
  119. let i;
  120. if (this._obj[key]) {
  121. if (!Array.isArray(this._obj[key])) {
  122. this._obj[key] = [this._obj[key], node.attributes];
  123. i = 1;
  124. }
  125. else {
  126. i = this._obj[key].push(node.attributes) - 1;
  127. }
  128. }
  129. else {
  130. this._obj[key] = node.attributes;
  131. }
  132. stack.push({ obj: this._obj, key, i });
  133. this._obj = node.attributes;
  134. };
  135. const onclosetag = () => {
  136. const parent = stack.pop();
  137. if (!parent) {
  138. return;
  139. }
  140. this._obj = parent.obj;
  141. const key = parent.key;
  142. const data = parent.i ?
  143. this._obj[key][parent.i] = cleanObj(this._obj[key][parent.i]) :
  144. this._obj[key] = cleanObj(this._obj[key]);
  145. if (!stack.length) {
  146. let skey = key === 'entry' || key === 'items' ? 'item' : key;
  147. // Some feeds will contain a summary of items at the top.
  148. // Ignore this.
  149. if (key !== 'items' || Array.isArray(data)) {
  150. parser.emit(skey, data);
  151. if (!this._buffer) {
  152. delete this._obj[key];
  153. }
  154. }
  155. }
  156. };
  157. }
  158. _write(chunk, encoding, callback) {
  159. this.parser.write(chunk, encoding);
  160. callback(null);
  161. }
  162. _final(callback) {
  163. this.parser.end();
  164. callback(null);
  165. }
  166. // Called when done parsing the document.
  167. // Returns entire document in object form.
  168. done() {
  169. if (!this._buffer) {
  170. return;
  171. }
  172. let items;
  173. if (this._root.item != null) {
  174. items = this._root.item;
  175. delete this._root.item;
  176. }
  177. else if (this._root.entry != null) {
  178. items = this._root.entry;
  179. delete this._root.entry;
  180. }
  181. else {
  182. items = [];
  183. }
  184. if (!Array.isArray(items)) {
  185. items = [items];
  186. }
  187. this._root.items = items;
  188. delete this._root.text;
  189. return this._root;
  190. }
  191. }
  192. exports.default = XMLFeedParser;
  193. //# sourceMappingURL=xmlfeedparser.js.map