Forum How do I...?

generate the correct beginning guide word?

EM
I recently discovered Prince and am very excited about it. I work for a specialty publisher, and I’ve been using a demo copy to test Prince’s capabilities because I think our document-generation procedures could enormously benefit from it. I wish to make a formal proposal to my higher-ups soon, but I’ve run into a deal-breaker of a problem!

Many of the documents we publish include alphabetized entries, like those you might find in a dictionary, phone book, glossary, gazetteer, etc. As a result, guide words are an essential component of our documents. I was delighted to discover that Prince has support for guide-word generation, but I haven’t been able to get it to achieve the results I need.

Here’s some sample CSS:
li span.guide {string-set: guideword content()}

@page:left {@top-left  {content: counter(page) "\A0\A0" string(guideword)}}
@page:right {@top-right {content: string(guideword, last) "\A0\A0" counter(page)}}

The above code is intended to produce one guide word per page: a beginning guide word on left-hand pages, and an ending guide word on right-hand pages. (It also displays page numbers.) And here’s some sample HTML to ply the above CSS on:
<li><span class="guide">ANDERSON</span>, Betty</li>
<li><span class="guide">ANDERSON</span>, Charlie</li>
<li><span class="guide">ARBOGAST</span>, Fred</li>

If there’s a page break (let’s say between pp. 3 & 4) between the “ANDERSON, Charlie” and “ARBOGAST, Fred” entries, Prince does what I expect, listing “ANDERSON” as pg. 3’s guide word and “ARBOGAST” as pg. 4’s. (Apparently string(guideword) is equivalent to string(guideword, first).) But, if the break occurs between the two “ANDERSON”’s, I get an undesired result: “ARBOGAST” becomes pg. 4’s guide word, even though the “ANDERSON, Charlie” entry is clearly the first one on the page. How do I fix this (so that “ANDERSON” would be the guide word on pg. 4 too)? Using string(guideword, start) is out, since other pages would get incorrect beginning guide words. Is there another way?

(Is the “first” page policy’s unexpected implementation due to a bug or a difference in philosophy? Apparently Prince considers the “first” value of the string to be the first one that’s different from the starting value [i.e., the first value that’s different from the last value from the previous page, if there is one]. But in documents like my company’s, sometimes nonunique guide words are needed as in cases like my example. In my conception, Prince’s behavior regarding the “first” page policy is legitimately needed for some documents, but it might be better renamed something like “first-new”, whereas just plain “first” should refer to the very first instance on the page, whether or not the value is a new one. Or, I suppose, “first” can remain as it is, and my desired page policy could be named something like “absolute-first”.)

I hope some sort of fix for my documents can be made available soon. Thank you for your attention. :)
EM
I’ve run across a workaround for my guide-word problem. First, I split my guideword variable into two, so that my left-page and right-page rules reference different variables, leftguideword and rightguideword:
@page:left {@top-left  {content: counter(page) "\A0\A0" string(leftguideword)}} 
@page:right {@top-right {content: string(rightguideword, last) "\A0\A0" counter(page)}}

Before I continue, I should explain that the sample HTML I gave in my previous post was simplified out of sympathy for the reader. :) For the purpose of my explanation, assume there’s at least one more element tagged inside each of my li elements:
<li><span class="guide">ANDERSON</span>, <span class="firstname">Betty</span></li> 
<li><span class="guide">ANDERSON</span>, <span class="firstname">Charlie</span></li> 
<li><span class="guide">ARBOGAST</span>, <span class="firstname">Fred</span></li>

(Note: that’s still a simplification!) I can then modify my string-set rules like this:
li span.guide {string-set: leftguideword content(), rightguideword content()}
li span.firstname {string-set: leftguideword "\D"}

This works! The idea is that the last li element on each right-hand page (and indeed every li element, but only the right-hand last is important) will reset leftguideword to a dummy value that I am certain will not ever occur as a valid potential guideword; so when the next left-hand page comes up, that page’s first instance of applying string-set to leftguideword is guaranteed to change the variable’s value, and therefore the desired guide word will appear atop the page. :D (Note: I haven’t tested this, but I assume a sibling selector [e.g., li span.guide ~ *] could also do the trick.)

Observations: This is a bit of a kludge. I still think the best solution would entail a page policy that permits the “absolute first” value of a variable as I described in my earlier post. Before that post, I had tried a tack somewhat similar to my eventual solution; note:
li span.guide::after {string-set: leftguideword "\D"}
I was surprised to discover in my experiments that ::after pseudoelements are invisible to string-set rules. Another tack would be to wrap my potential guide words in two elements, the inner of which would set the leftguideword variable to the dummy value; this sequencing does seem to produce the desired results, though I prefer to avoid adding such kludgy structure to my source HTML or XML.

Conclusions: I still have further testing to do before I make my proposal, but I’m feeling a lot better about the prospects of using Prince as part of our document-generation process. :D
mikeday
Those are very detailed observations and a clever workaround!

It does appear that our "first" value page-policy for the string-set property is sub-optimal, and it should really behave in the way that you describe (eg. the "absolute-first" page-policy suggestion).

Also, it could be handy if string-set also applied to before/after pseudo-elements as you pointed out.

We shall investigate both of these issues for a future release of Prince. Thank you for the excellent feedback! :D

Best regards,

Michael
mikeday
Today we have released Prince 5.1 rev 8, which has a fixed implementation of the string-set page policy and also supports string-set on pseudo-elements.

Thank you for reporting the issues! :)