jsoup icon indicating copy to clipboard operation
jsoup copied to clipboard

Is it possible to prettyprint document without adding newlines after a certain tag?

Open FishHawk opened this issue 1 year ago • 9 comments

I use jsoup to create epub. Here is the formatted xhtml file in the epub file. But some readers require that there should be no extra spaces or line breaks after <dc:language>. Is there a way to solve this?

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="pub-id">
 <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
  <dc:identifier id="pub-id">
   id
  </dc:identifier>
  <dc:title>
   title
  </dc:title>
  <dc:language>
   ja
  </dc:language>
  <dc:description>
   balabala
  </dc:description>
 </metadata>
 <manifest></manifest>
 <spine toc="toc.ncx"></spine>
</package>

FishHawk avatar Jun 10 '24 16:06 FishHawk

Currently there's no configurable way to change this. The default for unknown tags is to parse them as blocks.

I think it might make sense to parse unknown tags as "block + format-as-inline". That would prevent the line wrap when pretty-printing.

Or, perhaps, try and infer it by checking if the children are defined block tags or not.

jhy avatar Jul 01 '24 06:07 jhy

Got it. I'll just use string replacement for now.

FishHawk avatar Jul 02 '24 05:07 FishHawk

I took a pass at this (particularly, attempting to introduce a rule that only indents if an element contains other elements, but not if (all the other existing rules)). But it got too gnarly, as the rule needs to be implemented differently in each of Element outerHead, Element outerTail, and TextNode outerHead.

So, I'm declaring bankruptcy on the current pretty-printer implementation, and won't make other changes to it. I plan on refactoring it at some point to a strategy type object (which will provide more configurability) that will also maintain more state during the pass (a stack of what was indented, what requires white-space preservation, etc). With the goal of substantially simplifying the implementation and allowing better control, both by default and by users.

But for now, yeah, string replacement is your best bet...

jhy avatar Jul 09 '24 00:07 jhy

I took a pass at this (particularly, attempting to introduce a rule that only indents if an element contains other elements, but not if (all the other existing rules)). But it got too gnarly, as the rule needs to be implemented differently in each of Element outerHead, Element outerTail, and TextNode outerHead.

So, I'm declaring bankruptcy on the current pretty-printer implementation, and won't make other changes to it. I plan on refactoring it at some point to a strategy type object (which will provide more configurability) that will also maintain more state during the pass (a stack of what was indented, what requires white-space preservation, etc). With the goal of substantially simplifying the implementation and allowing better control, both by default and by users.

But for now, yeah, string replacement is your best bet...

I support removing pretty print as default, this feature makes lots of trouble, such as org.jsoup.Jsoup.parse("<a>a a</a>").select("a").text() which makes the doule whitespaces in "a a" joined into only single one, and this may bring in big trouble in practical applications!

anonyein avatar Jul 15 '24 03:07 anonyein

@anonyein I have covered this before in other issues: I prefer the pretty printer being on by default for HTML, and don't intend on changing that. It is off by default when using the XML parser, as we don't know the whitespace significance in XML. But we do in HTML and it generally appropriate and safe when serializing for downstream HTML parsers.

Let's keep this issue for the specific output change noted.

jhy avatar Jul 15 '24 06:07 jhy

@anonyein I have covered this before in other issues: I prefer the pretty printer being on by default for HTML, and don't intend on changing that. It is off by default when using the XML parser, as we don't know the whitespace significance in XML. But we do in HTML and it generally appropriate and safe when serializing for downstream HTML parsers.

Let's keep this issue for the specific output change noted.

I see. THX

anonyein avatar Jul 15 '24 06:07 anonyein

@anonyein I have covered this before in other issues: I prefer the pretty printer being on by default for HTML, and don't intend on changing that. It is off by default when using the XML parser, as we don't know the whitespace significance in XML. But we do in HTML and it generally appropriate and safe when serializing for downstream HTML parsers.

Let's keep this issue for the specific output change noted. @jhy Jsoup.parse("<a>a a</a>", "", Parser.xmlParser()).select("a").text() I still cannot get "a a"

anonyein avatar Jul 15 '24 07:07 anonyein

@anonyein like I said, please keep this issue focussed on the specific issue, not general pretty-print issues.

At any rate, .text() is completely unrelated from the pretty-printer. So any settings or discussions here are irrelevant. The pretty-printer is used only in the .html() methods.

If you read the Element.text() documentation you'll see it acts as described, and how to get non-normalized text.

jhy avatar Jul 15 '24 09:07 jhy

@anonyein like I said, please keep this issue focussed on the specific issue, not general pretty-print issues.

At any rate, .text() is completely unrelated from the pretty-printer. So any settings or discussions here are irrelevant. The pretty-printer is used only in the .html() methods.

If you read the Element.text() documentation you'll see it acts as described, and how to get non-normalized text.

I get it, using "wholeText" instead. Thanks for your help!

anonyein avatar Jul 15 '24 10:07 anonyein

I plan to get to this with #2286 Pretty Printer revamp

jhy avatar Mar 12 '25 01:03 jhy

Have implemented that now in the new Pretty Printer. When pretty-printing unknown tags (which in XML is all of them), jsoup will now default to treating them as inline. It also makes a simple heuristic to treat elements containing child elements as blocks.

So if you enable pretty-printing on XML, you will now get:

<dc:language>ja</dc:language>

Additionally, in #2285 I have introduced the ability to add and control settings for custom tags. So you can do this:

// can customize
Element meta = doc.expectFirst("metadata");
Tag metaTag = meta.tag();
metaTag.set(Tag.Block);
// set all the inner els of meta to be blocks
for (Element inner : meta) inner.tag().set(Tag.Block);

Gives us:

<package>
 <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
  <dc:identifier id="pub-id">id</dc:identifier>
  <dc:title>title</dc:title>
  <dc:language>ja</dc:language>
  <dc:description>desc</dc:description>
 </metadata>
</package>

(The Block setting will indent the element; but now by default if an element only has a textnode, that textnode won't be indented. This can be combined with Tag.InlineContainer.)

jhy avatar Apr 11 '25 05:04 jhy