Tools for learning Japanese.
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

60 righe
2.2 KiB

  1. import { Transform, TransformCallback } from 'stream';
  2. import { xml2json } from 'xml-js';
  3. export interface XmlToJsonLinesTransformStreamOptions {
  4. entryTagName: string;
  5. }
  6. class XmlToJsonLinesTransformStream extends Transform {
  7. private charactersToParse?: string;
  8. private readonly openTag: string;
  9. private readonly closeTag: string;
  10. constructor(options: XmlToJsonLinesTransformStreamOptions) {
  11. super();
  12. this.openTag = `<${options.entryTagName}>`;
  13. this.closeTag = `</${options.entryTagName}>`;
  14. }
  15. // eslint-disable-next-line no-underscore-dangle
  16. _transform(chunk: Buffer, _encoding: BufferEncoding, callback: TransformCallback) {
  17. try {
  18. const chunkStr = chunk.toString('utf-8');
  19. if (typeof this.charactersToParse !== 'string') {
  20. const firstEntryIndex = chunkStr.indexOf(this.openTag);
  21. this.charactersToParse = chunkStr.slice(firstEntryIndex);
  22. } else {
  23. this.charactersToParse += chunkStr;
  24. }
  25. let theCharacters = `${this.charactersToParse}`;
  26. let nextOpenTagIndex = theCharacters.indexOf(this.openTag);
  27. let nextCloseTagIndex = theCharacters.indexOf(this.closeTag);
  28. let sliceEnd = nextCloseTagIndex + this.closeTag.length;
  29. do {
  30. if (nextOpenTagIndex > -1 && nextCloseTagIndex > -1) {
  31. const xml = theCharacters
  32. .slice(nextOpenTagIndex, sliceEnd)
  33. .replace(/&(.+?);/g, '$1'); // FIXME better handling of XML entities??? This makes the pipe hang for some reason
  34. const json = xml2json(xml, { compact: true });
  35. this.push(`${json}\n`);
  36. theCharacters = theCharacters.slice(sliceEnd);
  37. }
  38. nextOpenTagIndex = theCharacters.indexOf(this.openTag);
  39. nextCloseTagIndex = theCharacters.indexOf(this.closeTag);
  40. sliceEnd = nextCloseTagIndex + this.closeTag.length;
  41. } while (nextOpenTagIndex > -1 && nextCloseTagIndex > -1);
  42. this.charactersToParse = theCharacters;
  43. callback(null, '');
  44. } catch (err) {
  45. callback(err as Error);
  46. }
  47. }
  48. }
  49. export const createXmlToJsonLines = (options = {
  50. entryTagName: 'entry',
  51. } as XmlToJsonLinesTransformStreamOptions) => new XmlToJsonLinesTransformStream(options);