heavysixer / node-pptx

Generate PPTX files on the server-side with JavaScript.
MIT License
155 stars 44 forks source link

multi lines was saved as 1 line #85

Open lengerrong opened 2 years ago

lengerrong commented 2 years ago

test code

  let pptx = new PPTX.Composer()
  await pptx.load(__dirname + '/../../templates/test.pptx')
  const tmpPPTX = '/tmp/worship' + Math.random() + '.pptx'  
  await pptx.save(tmpPPTX)

In the test.pptx, I have a slide which has two lines as its tile.

first line
second line

but the saved ppt always rendered to 1 line

first line second line

I looked into the codes, we are using xml2js.parseString to parse xml string to js obj. and use xml2js.Builder to save js obj back to xml string

with below code, we can easily reproduce the issue:

let xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><a:p><a:pPr marL="0" lvl="0" indent="0" algn="ctr" rtl="0"><a:spcBef><a:spcPts val="0"/></a:spcBef><a:spcAft><a:spcPts val="0"/></a:spcAft><a:buClr><a:schemeClr val="dk1"/></a:buClr><a:buSzPts val="1100"/><a:buFont typeface="Arial"/><a:buNone/></a:pPr><a:r><a:rPr lang="ja-JP" altLang="en-US"/><a:t>first line</a:t></a:r><a:br><a:rPr lang="en-CA" altLang="ja-JP" dirty="0"/></a:br><a:r><a:rPr lang="ja-JP" altLang="en-US"/><a:t>second line</a:t></a:r><a:endParaRPr lang="ja-JP" altLang="en-US" dirty="0"/></a:p>'

  xml2js.parseString(xml, function(err, js) {
    let builder = new xml2js.Builder({ renderOpts: { pretty: false } });
    let savexml = builder.buildObject(js);
    console.log(xml)
    console.log(savexml)
    console.log(xml === savexml)
  });

The output is:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><a:p><a:pPr marL="0" lvl="0" indent="0" algn="ctr" rtl="0"><a:spcBef><a:spcPts val="0"/></a:spcBef><a:spcAft><a:spcPts val="0"/></a:spcAft><a:buClr><a:schemeClr val="dk1"/></a:buClr><a:buSzPts val="1100"/><a:buFont typeface="Arial"/><a:buNone/></a:pPr><a:r><a:rPr lang="ja-JP" altLang="en-US"/><a:t>first line</a:t></a:r><a:br><a:rPr lang="en-CA" altLang="ja-JP" dirty="0"/></a:br><a:r><a:rPr lang="ja-JP" altLang="en-US"/><a:t>second line</a:t></a:r><a:endParaRPr lang="ja-JP" altLang="en-US" dirty="0"/></a:p>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><a:p><a:pPr marL="0" lvl="0" indent="0" algn="ctr" rtl="0"><a:spcBef><a:spcPts val="0"/></a:spcBef><a:spcAft><a:spcPts val="0"/></a:spcAft><a:buClr><a:schemeClr val="dk1"/></a:buClr><a:buSzPts val="1100"/><a:buFont typeface="Arial"/><a:buNone/></a:pPr><a:r><a:rPr lang="ja-JP" altLang="en-US"/><a:t>first line</a:t></a:r><a:r><a:rPr lang="ja-JP" altLang="en-US"/><a:t>second line</a:t></a:r><a:br><a:rPr lang="en-CA" altLang="ja-JP" dirty="0"/></a:br><a:endParaRPr lang="ja-JP" altLang="en-US" dirty="0"/></a:p>
false

As you can see in the output, the break line node was saved after the two lines rather than between them. That is the reason why multi line was saved into 1 line.

lengerrong commented 2 years ago

it is not xml2js lib's bug. since the json object parsed from the xml string do not have the sequence information.

{
  'a:p': {
    'a:pPr': [ [Object] ],
    'a:r': [ [Object], [Object] ],
    'a:br': [ [Object] ],
    'a:endParaRPr': [ [Object] ]
  }
}

and we won't be able to get below json object via xml2js lib.

{
  'a:p': {
    'a:pPr': [ [Object] ],
    'a:r': [[Object]],
    'a:br': [ [Object] ],
    'a:r': [[Object]],
    'a:endParaRPr': [ [Object] ]
  }
}
lengerrong commented 2 years ago

log a ticket to xml2js, hope can find a solution then. https://github.com/Leonidas-from-XIV/node-xml2js/issues/621