Named destination to an object in the PDF output

Post here questions and problems related to editing and publishing DITA content.
Sylvain_C
Posts: 4
Joined: Thu Sep 27, 2018 8:48 am

Named destination to an object in the PDF output

Post by Sylvain_C »

Hello everyone

I am looking to create a named destination in my custom output DITA-OT (1.8.5) based on pdf2.
The name of this destination comes from the 'outputclass' attribute.
This attribute will be set to <title> elements (topic, section or fig).

Has anyone ever done this or could give me a clue to do that?
Any help will be greatly appreciated.

Example (with section, but must also work with topic and fig):

Code: Select all

<section id="GUID-BAB3D609-C43B-437B-B229-D7F4733EFDF4">
<title outputclass="ds-maintenance" id="GUID-4790CD0F-C8D9-4DFF-A544-C4329E3C5871">Entretien</title>
<p>Les intervalles d’entretien dépendent des heures de fonctionnement de la machine.</p>
</section>
Result: A named destination 'maintenance' (outputclass value without the first three digits) is added to the PDF with the above element (<title> as target.

Note: I already have a customization on the topics titles to add chapter numbering.

PS: If someone has a solution other than an attribute to do that, I am also interested ;)

Sylvain
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi Sylvain,

You probably need an XSLT customization to generate an "<fo:wrapper id='GUID-BAB3D609-C43B-437B-B229-D7F4733EFDF4'/>" in the XSL-FO file.
Maybe you can search (Oxygen has a Find/Replace in Files utility) for the XSLT stylesheet from the PDF plugin which matches "topic/section", then override it in your XSLT customization to generate that wrapper.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Sylvain_C
Posts: 4
Joined: Thu Sep 27, 2018 8:48 am

Re: Named destination to an object in the PDF output

Post by Sylvain_C »

Hi Radu,

Thank you for your answer, but I do not understand the need to use a wrapper.
I may have misunderstood.
Here is what I thought to do in the custom.xsl file of my output (adding the middle part):

Code: Select all


    <xsl:template match="*[contains(@class, ' topic/topic ')]/*[contains(@class, ' topic/title ')]" mode="getTitle">
<xsl:variable name="topic" select="ancestor-or-self::*[contains(@class, ' topic/topic ')][1]"/>
<xsl:variable name="id" select="$topic/@id"/>
<xsl:variable name="mapTopics" select="key('map-id', $id)"/>
<fo:inline>
<xsl:apply-templates select="$mapTopics[1]" mode="topicTitleNumber"/>
</fo:inline>
<xsl:text> </xsl:text>
<xsl:apply-templates/>

Code: Select all


		<!-- outputclass detection -->
<xsl:choose>
<xsl:when test="self::*[contains(@outputclass, 'ds-')]">

<xsl:attribute name="destInPdf">
<xsl:value-of select="replace(@outputclass,'ds-','')"/>
</xsl:attribute>

<!-- *************** HOW TO CREATE A NAMED DESTINATION IN PDF
WITH destInPdf VALUE ??? *********** -->

</xsl:when>
</xsl:choose>

Code: Select all


    </xsl:template>
    
And I'm looking for how to create the named link in the .pdf file:

Image
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi Sylvain,

Any "id" attribute which you set on an XSL-FO element should be interpreted as a named destination in the PDF.
So you just need something like this:

Code: Select all

<xsl:attribute name="id">
<xsl:value-of select="replace(@outputclass,'ds-','')"/>
</xsl:attribute>
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Sylvain_C
Posts: 4
Joined: Thu Sep 27, 2018 8:48 am

Re: Named destination to an object in the PDF output

Post by Sylvain_C »

Oh yes,

Thank you Radu for your help.
I had already explored the possibility of modifying the id, but I did not understand that this attribute had to be in an XSL-FO element :oops:

Here is my customization for topic titles

Code: Select all

<!-- 20181004SCO support for the named destination in the outputclass attribute of the topic title -->
<xsl:template match="*[contains(@class,' topic/topic ')]/*[contains(@class,' topic/title ')]">
<xsl:variable name="topicType">
<xsl:call-template name="determineTopicType"/>
</xsl:variable>
<xsl:choose>
<!-- Disable chapter title processing when mini TOC is created -->
<xsl:when test="(topicType = 'topicChapter') or (topicType = 'topicAppendix')" />
<!-- Normal processing -->
<xsl:otherwise>
<xsl:apply-templates select="." mode="processTopicTitle"/>
</xsl:otherwise>
</xsl:choose>

<!-- named destination in the outputclass attribute -->
<xsl:choose>
<xsl:when test="self::*[contains(@outputclass, 'ds-')]">
<fo:block-container height="0mm" width="0mm">
<fo:block padding-top="-7.2mm">
<xsl:attribute name="id">
<xsl:value-of select="replace(@outputclass,'ds-','')"/>
</xsl:attribute>
</fo:block>
</fo:block-container>
</xsl:when>
</xsl:choose>
</xsl:template>
And my customization for section titles

Code: Select all

<!-- 20181004SCO support for the named destination in the outputclass attribute of the section title -->
<xsl:template match="*[contains(@class,' topic/section ')]/*[contains(@class,' topic/title ')]">
<fo:block xsl:use-attribute-sets="section.title">
<xsl:call-template name="commonattributes"/>
<xsl:apply-templates select="." mode="getTitle"/>
</fo:block>

<!-- named destination in the outputclass attribute -->
<xsl:choose>
<xsl:when test="self::*[contains(@outputclass, 'ds-')]">
<fo:block-container height="0mm" width="0mm">
<fo:block padding-top="-4mm">
<xsl:attribute name="id">
<xsl:value-of select="replace(@outputclass,'ds-','')"/>
</xsl:attribute>
</fo:block>
</fo:block-container>
</xsl:when>
</xsl:choose>
</xsl:template>
It works according to my wish.
Thank you again for the help you provided.

Best regards
Sylvain
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi Sylvain,

Great, thanks for posting a solution for people who might read the thread later on.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

When did DITA OT start generating named destinations for IDs?
We generate PDF documents using DITA OT, converting first to FO and then on to PDF. But we don't get any named destinations in the PDFs at all, though all elements have IDs, like this:

Code: Select all

<subsec1 id="subsec1_BE8049C4430E45639C1B7E9965707537" ...></subsec1>
Instead, I have had to manually add elements like this to the FO file before conversion to PDF:

Code: Select all

<!-- These two elements were added to create a named destination with a custom name -->
<fox:destination internal-destination="section1"/><fo:inline id="section1" />
<!-- The following is what DITA OT generated -->
<fo:block font-size="9pt" id="unique_2_Connect_42_subsec1_BE8049C4430E45639C1B7E9965707537">...
I am not sure if I understand your solution correctly, but it looks simpler...?
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi,

If you set an @id attribute with a certain value on almost any XSL-FO element (fo:inline, fo:block, fo:wrapper), in the generated PDF you will have a named destination with that corresponding ID value.
The way in which that @id attribute is set on the XSL-FO elements depends on how your XSLT customization is written.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

Do you know when that became the standard behavior?
Granted, we are currently still using DITA-OT 1.8 and Apache-FOP 1.1, but still:
Almost all our elements have ID's:

Code: Select all

<fo:block id="unique_3_Connect_42_p_DF7A55AB5C754EA9B3B7FD11D2839E2A" space-after="3pt" space-before="1pt" text-align="left" text-indent="0em">
But still no named destinations are created:

Image

Also even the documentation for the "trunk" (latest) version of Apache-FOP implicitly says you have to explicitly specify named destinations:
It is possible that in some future release of FOP, all elements with "id" attributes will generate named-destinations, which will eliminate the need for fox:destination.
Source: https://xmlgraphics.apache.org/fop/trun ... stinations
Sylvain_C
Posts: 4
Joined: Thu Sep 27, 2018 8:48 am

Re: Named destination to an object in the PDF output

Post by Sylvain_C »

In my case, the ID's on the elements are given by the CMS we use.
I wanted to have a named destination in addition with a predefined name. This destination is used by an external system and the names are defined by another department (unique_xxxxxxxx is not suitable, and can change from one output to another).

Best regards.
Sylvain
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

Yes, I also want to have custom named destinations ("chapter3" sounds better than a long GUID) and I'm not sure if we can just modify the existing GUID's or if they are used elsewhere.
But I was still surprised to learn that apparently all ID's are now automatically converted to named destinations? Because I can't reproduce that.
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi Marvin,

I looked more into this and you are right, sorry about my confusion, somehow besides generating an XSL-FO element with a certain ID, you also need to add a fox:destination element to defined that ID as a named anchor.
So from my tests the XSL-FO output would need to look something like this:

Code: Select all

               <fox:destination internal-destination="NAMED_DESTINATION" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"/>
<fo:block id="NAMED_DESTINATION" ...>

</fo:block>
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

Ah, ok. Thank you for checking!

What would you recommend for getting "pretty" named destinations? Apparently it's not possible to create a named destination that points to a different ID.
Would you just outright change the ID of the original block elements then or instead add a new element with a "pretty" ID to be used for the named destination, like I have done? And if adding a new element is the way to go, would you add a block, inline or wrapper element, or something completely different?
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi,

I think adding a new element would be the way to go. "fo:wrapper" can be included mostly anywhere and it does not change the layout in any way so if you test it and it works you could use that.
Indeed the original @id attribute set on an element is changed to an unique ID in the transformation temporary files folder before the XSLT is applied. But the original value is preserved in a new attribute called "oid" set on the same element on which the initial @id was set.
Looking more at the publishing side at some point in DITA OT 3.1 a certain xsl:template was added to simplify the addition of named anchors:

https://github.com/dita-ot/dita-ot/pull/2984

so if you are using a new version of the DITA OT (3.1.0 or newer) the XSLT for adding named anchors for each element containing a title would look something like this:

Code: Select all

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="2.0">
<xsl:template match="*" mode="customTopicAnchor">
<xsl:if test="parent::*[@oid]">
<fox:destination internal-destination="{parent::*/@oid}" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"/>
<fo:wrapper id="{parent::*/@oid}"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
That xsl:template "<xsl:template match="*" mode="customTopicAnchor">" gets called for any DITA <title> element so this is why I look at the parent element for the @oid attribute containing the original value of the ID.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

Thank you! Unfortunately our ID's are just GUID's, so the oid's wouldn't help. But then I'll just use an <fo:wrapper>. Thanks!
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

By the way, is there a way to identify objects from the FO file in the (default) PDF export, based on their ID or so?
Or is all that information removed if you don't explicitly insert it using named destinations or such?
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi,

From what I think those IDs defined on the XSL-FO elements are somehow still inside the PDF (as they are used for internal linking) but they cannot be used as outside anchors (as they have not been defined as named destinations).

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

That would be fine.
Our issue is this: In the PDF we currently only have internal links, but no links to other documents.
There are <xref> tags in the source, but links to other documents are disabled by prepending a '#' to the destination.
I would like to add named destinations as well as links between documents.

Of course the correct approach would be to modify the .fo files as we've discussed, but I'm wondering if I could build a quick fix for the time being, as we can't necessarily regenerate all PDF documents at this point.
It would be great if I could just add named destinations in the PDFs and then connect them to the (disabled) cross-references - provided that both links and their destinations are still detectable using their ID.
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi Marvin,

If you want to add named destinations to PDFs without re-generating them from the DITA content, there might be various libraries which can be used to load and modify a PDF.
For example for our Oxygen Chemistry engine (which builds a PDF by using CSS to customize XML content) we use the free Java Apache Fontbox project:

https://pdfbox.apache.org/

to load the PDF document and make changes to it after it has been produced. But you would probably need a Java developer for this.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

Hi Radu,

I am a software developer myself, so implementing this wouldn't be a problem.
The challenge here is identifying the links and their destinations. Do you happen to know where I could find the ID's in the PDF's using one of the many PDF libraries?

Thanks,
Marvin
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi Marvin,

I do not know exactly how this could be done.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Marvin
Posts: 22
Joined: Thu Oct 04, 2018 7:26 pm

Re: Named destination to an object in the PDF output

Post by Marvin »

After looking at the PDFs using the Aspose PDF library, I don't think they contain information about the original ID's, unless named destinations are specified in the .fo file.
Internal links within the same PDF document namely do not seem to point to any sort of ID, but instead they simply say "Go to position X,Y on page Z".
So I guess the only way to fix this is indeed to regenerate the PDF documents from modified .fo files.
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi Marvin,

Yes, possibly, I also did not find a precise solution to add named destinations to an existing PDF. Thanks for updating this thread.

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
kirkilj
Posts: 108
Joined: Fri May 14, 2010 12:14 am

Re: Named destination to an object in the PDF output

Post by kirkilj »

Radu wrote: Tue Oct 09, 2018 8:54 am Hi Marvin,

I looked more into this and you are right, sorry about my confusion, somehow besides generating an XSL-FO element with a certain ID, you also need to add a fox:destination element to defined that ID as a named anchor.
So from my tests the XSL-FO output would need to look something like this:

Code: Select all

               <fox:destination internal-destination="NAMED_DESTINATION" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"/>
               <fo:block id="NAMED_DESTINATION" ...>
               
               </fo:block>
Regards,
Radu
Hi Radu, I looked at the PDF generated by your XSL-FO FOP transformation and didn't see any Named Destinations using a PDF viewer with the ability to see all named destinations, so I guess this isn't an option. We just want to generate a named destination for any DITA element with an @id value for starters.

Since we're using our own pipeline currently, would the best place to inject the fox:destination elements as you describe be in a template located in a file such as

Code: Select all

our.custom.pdf.plugin.loc/xsl/fo/link_fop.xsl"
where we copy the id of the target element into the internal-destination attribute?
Radu
Posts: 8092
Joined: Fri Jul 09, 2004 5:18 pm

Re: Named destination to an object in the PDF output

Post by Radu »

Hi John,
This is a forum thread from 4 years ago, maybe you could have started a new one.
So about this usecase:
We just want to generate a named destination for any DITA element with an @id value for starters.
So your XSLT stylesheet needs to create <fox:destination> XSL-FO elements before all elements containing @id attributes... I'm not sure if this could be done in general, without the need to overwrite each xsl:template which produces each element. Maybe do something like this:

Code: Select all

  <xsl:template match="*[@id]" priority="10000">
    <fox:destination internal-destination="{@id}"/>
    <xsl:next-match/>
  </xsl:template>
From what I remember our DITA to PDF transformation using CSS already produces named destinations from all IDs:
https://www.oxygenxml.com/doc/versions/ ... aid-title4

Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
Post Reply