Subject: Docbook 5.x

From: Jürgen Purtz <[email-masked]>
Date: Wed, 20 Apr 2016 16:30:27 +0200

Hi,
actually we use DocBook V4.2 for the PostgreSQL manuals. I suggest an 
upgrade to DocBook 5.x. This sounds simple, but it will be a long 
process with many sub-tasks.

Rationale:

  * Sooner or later we MUST migrate as the 4.x series is outdated: V4.2
    dates back to 2002. The 4.x series is no longer actively developed
    since 2006. See: http://www.docbook.org/tdg5/en/html/ch01.html "In
    October 2006, the DocBook Technical Committee released DocBook V4.5,
    the last release planned in the 4.x series."
  * V5.0 is available since 2009. See:
    http://www.docbook.org/tdg5/en/html/ch01.html: "DocBook V5.0 became
    an official Committee Specification in June 2009 and became an
    official OASIS Standard in October 2009."
  * Actually the technical committee has the third Candidate Release for
    V5.1.

PROs:

  * The formal part of the migration is supported by existing tools:
    http://docbook.org/docs/howto/#convert4to5 (nevertheless some
    scripts written by ourself will be necessary).
  * The normative schema for Docbook 5.x is written in RELAX NG.
    Additionally the technical committee converts this normative schema
    to a XSD schema and to DTD, which are not normative but very near to
    RELAX NG and will fit for most applications. Hence, we have the
    choice between three schema syntaxes and everybody can use his
    favourite one.
  * Our source file format will switch from SGML to XML. This implies
    that we have access to all XML features like XLink, XPath, XSLT,
    XSL-FO, SVG, MathML, namespaces, ... .

CONs:

  * The migration from 4.x to 5.x implies major changes at 3 different
    levels.
      o DocBook structure: Previously it was defined in SGML syntax
        (DTD). Now it is defined in RELAX NG schema language plus
        Schematron rules.
      o DocBook files: Previously we used SGML syntax for our files. We
        must convert them to a valid XML syntax, eg: tag omission.
      o Tools and style sheets: All tools which operate at the native
        SGML-level (editors, conversions, ...) must be replaced by XML
        conforming tools. As valid XML implicitly conforms to a valid
        SGML syntax this step may be accomplished by reconfiguring some
        of the tools, eg.: .emacs.

What I have done so far is:

  * Conversion of sgml files to valid xml syntax with a perl skript. I
    failed to use 'osx' or 'spam'.
  * Conversion of these xml files to Docbook5.x format using xsltproc
    and Docbooks xslt-migration skripts.
  * Creation of html files using xsltproc and Docbooks xslt skripts.
  * Creation of fo files using xsltproc and Docbooks xslt skripts.
  * Creation of pdf files using fop.
  * The conversions needs less than 10 minutes on a Intel i5 processor.

This is a very first raw round-trip with one output file per sgml file 
and output type. Not supported: entities (__gt__ as a surrogate), 
<[CDATA and similar SGML constructs, PostgreSQL specific style sheets, 
Makefile, additional errors occur, .... .  I append one file of every 
new format for the chapter "Advanced Features": xml (the new source), 
html, fo, pdf.

Any ideas or suggestions? Shall we go further on this way? Has anybody 
more experiences in SGML-->XML conversions or Docbook 4.x --> 5.x 
conversions?

Kind regards
Jürgen Purtz

-- 
Sent via pgsql-docs mailing list ([email-masked])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-docs

---

From: Alexander Law <[email-masked]>
Date: Wed, 20 Apr 2016 18:59:05 +0300

Hello Jürgen,

Please look at the discussion that we had some time ago:
http://www.postgresql.org/message-id/[email-masked]

And we (postgrespro) still have plans to migrate to XML as soon as we 
get documentation translated.
We had no issues with SGML->XML conversion, "make postgres.xml" creates 
XML (with entities and alike), which we use.

When you talking about "conversion of html, fo, pdf, ..." do you mean 
using docs/sgml/Makefile or some other scripts?

As to conversion SGML to XML, we need to decide whether to generate a 
single XML, or a set of XMLs (corresponding to current SGMLs).
In the latter case - how to include XML-fragments into the main document 
(as entities or with xi:include)?

Please, can you explain what are "Docbooks xslt-migration scripts"?
Is Docbook 4.x incompatible with Docbook 5.x and we need to convert it 
additionally?

Best regards,
Alexander

-----
Alexander Lakhin
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

20.04.2016 17:30, Jürgen Purtz пишет:
>   * Sooner or later we MUST migrate as the 4.x series is outdated:
>     V4.2 dates back to 2002. The 4.x series is no longer actively
>     developed since 2006. See:
>     http://www.docbook.org/tdg5/en/html/ch01.html "In October 2006,
>     the DocBook Technical Committee released DocBook V4.5, the last
>     release planned in the 4.x series."
>     http://www.docbook.org/tdg5/en/html/ch01.html: "DocBook V5.0
>     became an official Committee Specification in June 2009 and became
>     an officia7l OASIS Standard in October 2009."
>   * Actually the technical committee has the third Candidate Release
>     for V5.1.
>
>
> PROs:
>
>     Additionally the technical committee converts this normative
>     schema to a XSD schema and to DTD, which are not normative but
>     very near to RELAX NG and will fit for most applications. Hence,
>     we have the choice between three schema syntaxes and everybody can
>     use his favourite one.
>       o DocBook files: Previously we used SGML syntax for our files.
>         We must convert them to a valid XML syntax, eg: tag omission.
>         SGML syntax this step may be accomplished by reconfiguring
>         some of the tools, eg.: .emacs.
>

---

From: Simon Riggs <[email-masked]>
Date: Wed, 20 Apr 2016 19:41:26 +0100

On 20 April 2016 at 15:30, Jürgen Purtz <[email-masked]> wrote:

>    - Conversion of sgml files to valid xml syntax with a perl skript. I
>    - Conversion of these xml files to Docbook5.x format using xsltproc
>    - Creation of html files using xsltproc and Docbooks xslt skripts.
>    - Creation of fo files using xsltproc and Docbooks xslt skripts.
>    - Creation of pdf files using fop.
>    - The conversions needs less than 10 minutes on a Intel i5 processor.
>
> So you believe you have/can convert between the two formats accurately, so
we can change things in a single commit?

What verification is offered? Possible?

And that is ready to go now? Will you post your perl script, or the patch?
Other projects use the same file formats, e.g. Slony, XL etc

If an automatic migration is possible do we need to change at all?

-- 
Simon Riggs                http://www.2ndQuadrant.com/
<http://www.2ndquadrant.com/>
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

---

From: Jürgen Purtz <[email-masked]>
Date: Thu, 21 Apr 2016 15:34:31 +0200

On 20.04.2016 20:41, Simon Riggs wrote:
> On 20 April 2016 at 15:30, Jürgen Purtz <[email-masked] 
> <mailto:[email-masked]>> wrote:
>
>       * Conversion of sgml files to valid xml syntax with a perl
>         skript. I failed to use 'osx' or 'spam'.
>       * Conversion of these xml files to Docbook5.x format using
>         xsltproc and Docbooks xslt-migration skripts.
> So you believe you have/can convert between the two formats 
> accurately, so we can change things in a single commit?
>
> And that is ready to go now? Will you post your perl script, or the 
> patch? Other projects use the same file formats, e.g. Slony, XL etc
>
> Simon Riggs http://www.2ndQuadrant.com/ <http://www.2ndquadrant.com/>

Hi,

actually I have done only a first raw round-trip to evaluate that there 
is no showstopper for my plans. If we find a consensus in the community 
that this work is valuable for the postgres documentation I will 
continue to work on it in the near future. To answer your questions:

  * "do we need to change at all?". This question has to be discussed in
    the community. I tried to use the recommended tools like 'osx' and
    'spam' - and failed (not at all but in details like newline
    processing). This may be a my fault, or it results from the fact
    that we still use sgml instead of xml. But over time this task will
    get harder and harder: sgml knowledge gets lost, sgml-tools are no
    longer actively developed, xml move foreward, ...
  * Actually I don't see any showstopper. Therefore I believe that the
    conversion from Docbook 4 to 5 is manageable. The plan is that we
    will have one xml-file in db5 format per every sgml file in db4 format.
  * To support the repository in a continuous way we shall do something
    like 'git mv file.sgml file.xml', put the new content to 'file.xml'
    and 'git commit'. Additionally the newlines must be kept during all
    conversation steps.
  * Maybe some very individual (manual) steps are necessary, but it
    shall be possible that also this can be scripted. Therefore the
    conversion shall run fast and a single commit shall work on the
    complete documentation.
  * There are no special "Postgres" tasks in the Perl script or at any
    other places. It depends on docbook only. Therefore other projects
    can use it in the same way. Of course I will publish all sources.
  * Actually I try to generate well-formed xml. Validation against the
    Docbook 5 schema will follow.

Alexander Law posted additional suggestions and questions:

    Hello Jürgen,

    And we (postgrespro) still have plans to migrate to XML as soon as
    we get documentation translated.
    We had no issues with SGML->XML conversion, "make postgres.xml"
    creates XML (with entities and alike), which we use.

    When you talking about "conversion of html, fo, pdf, ..." do you
    mean using docs/sgml/Makefile or some other scripts?

    As to conversion SGML to XML, we need to decide whether to generate
    a single XML, or a set of XMLs (corresponding to current SGMLs).
    In the latter case - how to include XML-fragments into the main
    document (as entities or with xi:include)?

    Please, can you explain what are "Docbooks xslt-migration scripts"?
    Is Docbook 4.x incompatible with Docbook 5.x and we need to convert
    it additionally?

    Best regards,
    Alexander

    -----
    Alexander Lakhin

My answers:

  * Docbook 4 and 5 are not compatible. There are new elements, others
    have gone and are replaced by more generic ones. But the Docbook
    project offers xslt's to convert Docbook 4 xml-files to Docbook5
    xml-files.
  * There are pros and cons using postgres.xml as a starting point. PRO:
    well formed (and valid?) xml format. Entities keeps alive. No more
    "<![CDATA[", "<![%include" and similar sgml constructs. CON: Only
    one file. Ugly line break algorithm.
  * Actually I don't use the existing Makefile. I start Perl, xsltproc
    and fop with a different script. If I continue to work, I have to
    change the Makefile.
  * "how to include XML-fragments into the main document (as entities or
    with xi:include) ?". As described above, I prefer one file per
    existing sgml-file. But some of those sgml-files have more than one
    root element. It such situations (and without further processing)
    the resulting xml-files will have fragments. In general it will be
    more "Docbook 5 compliant" to use xi:include instead of entities.
  * "Docbooks xslt-migration scripts": see:
    http://docbook.org/docs/howto/#convert4to5

Kind regards
Jürgen Purtz

---

From: Jürgen Purtz <[email-masked]>
Date: Tue, 3 May 2016 21:19:40 +0200

Hello,

the conversion of PostgreSQL documentation from Docbook 4.x to 5.x 
consists of the following steps:

 1. pure sgml --> xml conversion (done, Perl script)
 2. 4.x markup --> 5.x markup (done, Docbook standard migration script)
 3. post-processing of 5.x files (done, Perl: xi:include, entities, ...)
 4. generate the complete file postgres_all.xml with xmllint (done)
 5. generate online documentation (html, man, text)
 6. generate print documentation (rtf, pdf)
 7. adopt Makefile to the new situation

After step 3 we have well-formed xml files, most of them are valid 
against Docbook 5.0 xsd. Actually the following non-valid situations occur:

  * a lot of unknown xref targets, as the target exists in a different file
  * 4 remaining sgml-entities: standalone-xxx and include-xxx
  * some markups, which are not valid in 5.x, mostly with <synopsis> and
    <function>. This must be resolved manually (5.x offers comprehensive
    possibilities for very detailed markups with <funcsynopsis> and
    <cmdsynopsis>)

Steps 5 and 6 implies the replacement of our dsssl script with xslt 
scripts. I guess that this is much more difficult and lengthy than 
everything else I have done in this project so far. Furthermore I don't 
have any knowledge about dsssl. And this is the reason why I write this 
mail. Is anybody out there who can support me for the dsssl --> xslt 
conversion - or at least can answer questions like:

  * Is our file stylesheet.dsl written from scratch - or is it derived
    from any docbook 1/2/3/4.x generic stylesheet?
  * Which person has developed this file?
  * What is the role of the *.xsl files in the sgml-directory and how do
    they collaborate with stylesheet.dsl?

Regards, Jürgen

---

From: Alvaro Herrera <[email-masked]>
Date: Tue, 3 May 2016 16:34:42 -0300

Jürgen Purtz wrote:
> upgrade to DocBook 5.x. This sounds simple, but it will be a long process
> with many sub-tasks.

Yes, agreed.  The killer objection placed last time was that it took
something like 10x longer to generate the HTML using the XML-based
toolchain than the SGML-based ones.  If this is not fixed, let's forget
about this whole thing until it is.  So, would you time the process
using both toolchains and report back?

-- 
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

---

From: "Joshua D. Drake" <[email-masked]>
Date: Tue, 3 May 2016 12:59:02 -0700

> using both toolchains and report back?

IIRC:

TGL submitted a patch for the openjade bug way back when that caused 
that issue.

TGL, do you know what happened there?

Sincerely,

JD

-- 
Command Prompt, Inc.                  http://the.postgres.company/
                         +1-503-667-4564
PostgreSQL Centered full stack support, consulting and development.
Everyone appreciates your honesty, until you are honest with them.

---

From: Oleg Bartunov <[email-masked]>
Date: Tue, 3 May 2016 23:13:21 +0300

> using both toolchains and report back?

As it stated in
http://www.postgresql.org/message-id/[email-masked]
the xml performance may be greatly improved. Alexander, what is current
state of art of your patch ? How slow is xml in compare to sgml ?

---

From: Tom Lane <[email-masked]>
Date: Tue, 03 May 2016 16:55:10 -0400

> TGL submitted a patch for the openjade bug way back when that caused 

I think you're thinking of this:
http://www.postgresql.org/message-id/[email-masked]

I do not recall just when/how that got resolved upstream, or if they
ever even responded to me.  But it must have been resolved, because the
performance before that was patched was untenable even then, and would be
far more so now considering how much our docs have grown since 2006.
I have not heard anyone complaining lately that PDF output takes three
days to build.

In short, I doubt that that's relevant anymore.  If it was, it would
certainly not be favorable to the XML toolchain.

BTW, the thread that that message is embedded in is pretty relevant,
because it was all about yet another lets-switch-to-XML proposal...

			regards, tom lane

---

From: Tom Lane <[email-masked]>
Date: Tue, 03 May 2016 17:05:06 -0400

> far more so now considering how much our docs have grown since 2006.

Actually, further digging suggests that Peter found a way to hack our
stylesheets to avoid that openjade bug:

http://www.postgresql.org/message-id/[email-masked]
http://git.postgresql.org/gitweb/?p=postgresql.git&a=commitdiff&h=465269b8a

So it's possible that the openjade bug is still there, but has been
defanged for our purposes.  In any case, there's still little reason
to think that it would apply to a different toolchain.

			regards, tom lane

---

From: Peter Eisentraut <[email-masked]>
Date: Tue, 3 May 2016 20:44:00 -0400

> state of art of your patch ? How slow is xml in compare to sgml ?

Please make sure the patch is registered in the next commit fest.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

---

From: Jürgen Purtz <[email-masked]>
Date: Wed, 4 May 2016 16:44:34 +0200

Hello,

I measured following elapsed times on an Intel i5 processor:

 1. generate all HTML files with dsl script (make html): 0:48 min.
 2. generate all HTML files with xslt script (make xslthtml): 16:01 min.
 3. generate all HTML files with xslt script in the new environment
    (pure Docbook5): 4:07 min.
 4. Generating different things via dsl scripts in the new environment
    may be possible. But the changelog of the Docbook5 dsl scripts
    shows, that the last modification occurred in 2004 - this way is a
    dead end.

There is one principle and a lot of minor differences between 2 and 3. 
Solution 2 is based on an xml-file and xslt scripts which are based on 
Docbook4. The basic difference to 3 is, that in 3 everything is Docbook5 
compliant: there are only Docbook5 xml- and xslt-files (as my workflow 
is: db4 --> xml --> db5 -- (db5 xslt) --> html). The minor differences 
concerns the fact, that actually there are errors in my xml files and 
that I made only a few parameterisation to the Docbook5 standard xslt 
files - no optimization at all.

I used following tools: perl, xmllint and xsltproc. osx and OpenJade are 
obsolete in the new environment (so far, there is much more work to do).

Jürgen Purtz

On 03.05.2016 22:13, Oleg Bartunov wrote:
>
>
> On Tue, May 3, 2016 at 10:34 PM, Alvaro Herrera 
> <[email-masked] <mailto:[email-masked]>> wrote:
>
>     Jürgen Purtz wrote:
>     > Hi,
> the xml performance may be greatly improved. Alexander, what is 
> current state of art of your patch ? How slow is xml in compare to sgml ?
>
>
>
>     --
>     Sent via pgsql-docs mailing list ([email-masked]
>     <mailto:[email-masked]>)

---

From: Tom Lane <[email-masked]>
Date: Wed, 04 May 2016 10:51:17 -0400

>     shows, that the last modification occurred in 2004 - this way is a

Ouch.  What about output to PDF?  While we don't care as much about
that as HTML for day-to-day use, it has to be feasible (ie, not hours).

			regards, tom lane

---

From: Alexander Law <[email-masked]>
Date: Wed, 4 May 2016 18:08:57 +0300

Hello Jürgen,

As was stated in the aforementioned thread, solution 2 can be much (8x) 
faster with some xslt optimizations, but I think now we should outline 
some roadmap before we start to prepare patches and so.
Maybe we should convert to XML with DocBook4 at first step?
Then, once we get everything stabilized, we can upgrade to DocBook5.
Shouldn't we decompose the conversion procedure, so we could perform 
fully automatic conversion without any manual changes, and then fix 
non-valid situations, you described before?

And one more question - Is conversion to DocBook5 your final goal? Or 
maybe you have any further plans regarding documentation, such as 
translating it to Deutsch?

Best regards,
Alexander

04.05.2016 17:44, Jürgen Purtz пишет:
> Docbook4. The basic difference to 3 is, that in 3 everything is 
> Docbook5 compliant: there are only Docbook5 xml- and xslt-files (as my 
> workflow is: db4 --> xml --> db5 -- (db5 xslt) --> html). The minor 
> differences concerns the fact, that actually there are errors in my 
> xml files and that I made only a few parameterisation to the Docbook5 
> standard xslt files - no optimization at all.
>
> I used following tools: perl, xmllint and xsltproc. osx and OpenJade 
> are obsolete in the new environment (so far, there is much more work 
> to do).
>
> Jürgen Purtz
>
>
>
>> <[email-masked]> wrote:
>>
>>     Jürgen Purtz wrote:
>>     > Hi,

---

From: Alvaro Herrera <[email-masked]>
Date: Wed, 4 May 2016 12:18:48 -0300

>    shows, that the last modification occurred in 2004 - this way is a

Thanks.

The dsl toolchain has a "make html" format which creates the index and a
"make draft" that doesn't.  You timed the former only.  What's the
timing for an equivalent of "make draft" in the xslt chain?  If it
exists and is short enough, it seems acceptable to me that the complete
(with index) build takes ~4x as long as today; the draft timing is more
critical, I would think.

Man pages are already generated using xslt, so I suppose that wouldn't
change.  PDF creation timing is also critical.

FWIW, in my laptop "make draft" takes 1m18.788s and a "make html"
takes 1m26.676s.  So it's just 8 seconds to generate the SGML file for
the index, and no reruns required ... hmm.  I think I'm gonna forget
about "make draft" in the future.

---

From: Alvaro Herrera <[email-masked]>
Date: Wed, 4 May 2016 12:21:58 -0300

Alexander Law wrote:
> faster with some xslt optimizations, but I think now we should outline some
> roadmap before we start to prepare patches and so.

Can the Docbook5 build be sped up with similar hacks?

If the stylesheet tweaks you did are universally useful, why not
contribute them back to upstream Docbook?

> Then, once we get everything stabilized, we can upgrade to DocBook5.

Not sure there's much point in having an intermediate step in the
repository that makes the doc build so much slower.  I'd rather go to
Docbook5 straight away.

> Shouldn't we decompose the conversion procedure, so we could perform fully
> automatic conversion without any manual changes, and then fix non-valid
> situations, you described before?

I don't think so -- this means leaving a state in the repo in which the
docs don't actually build.

---

From: Jürgen Purtz <[email-masked]>
Date: Wed, 4 May 2016 17:30:18 +0200

> that as HTML for day-to-day use, it has to be feasible (ie, not hours).

Actually I made tests using fop on single files (the converted sgml 
files). This works within seconds and in my very first mail from 
2016-04-20 I added the results for the 'advanced.xml' file. When I try 
to convert the complete 'postgres_all.xml' file, fop crashes after some 
minutes. As fop is a Java application, it is possible that the assigned 
main memory is short (-Xms -Xmx, ...) - or it comes from some other Java 
specific issues. I will work on this in the next days.

Jürgen Purtz

---

From: Tom Lane <[email-masked]>
Date: Wed, 04 May 2016 11:31:48 -0400

> (with index) build takes ~4x as long as today; the draft timing is more

I would object to that; I don't ever use "make draft", in part because
I frequently want to look at whether the index entries look sensible.
Also, as you noted, the time savings is pretty minimal at present.

			regards, tom lane

---

From: Alexander Law <[email-masked]>
Date: Wed, 4 May 2016 18:34:53 +0300

Hello Alvaro,
> contribute them back to upstream Docbook?
I can't guarantee that these tweaks with work for all the DocBook 
documents, though I've made sure that the result is the same for the 
postgresql doc html's (as I stated in 
http://www.postgresql.org/message-id/[email-masked]).

> docs don't actually build.
I mean we could build the docs just as we do it now (as DocBook4). So we 
can continue to use existing toolchain (and Makefile as it can generate 
html and pdf from XML), just change a format for now.

---

From: Jürgen Purtz <[email-masked]>
Date: Wed, 4 May 2016 18:52:36 +0200

On 04.05.2016 17:08, Alexander Law wrote:
> As was stated in the aforementioned thread, solution 2 can be much 
> (8x) faster with some xslt optimizations, but I think now we should 
> outline some roadmap before we start to prepare patches and so.

Hello Alexander,

I havn't seen your xslt optimization so far. What have you done? Where 
can I find the optimized script or a description?

"Divide and conquer" is a good strategy and people use it in many cases. 
As you have stated, there are two major steps: from db4-sgml to db4-xml 
and from there to db5-xml. In parallel to the second one we shall 
migrate from dsl scripts to db5-xslt scripts. Your idea to go step by 
step and stabilise at the intermediate level is good in general. But in 
this case it may be unnecessary. The first step is very small. It 
consists mainly of the elimination of shorttags and empty elements. This 
is a pure formal act without risk. If we would stop at this point, 
people are forced to switch their environment, eg .emacs from db4-sgml 
to db4-xml - and after the second step to db5-xml. This is possible - 
but the twice changing will bring (possibly) more confusion than 
advantages. The real challenge is the second step as it implies some 
manual modifications (entities, non-valid markup in sense of db5-schema) 
and a switch to a different output chain. Maybe we can live for a while 
with some files, which are not valid against db5-schema - as far as the 
output chain produces correct results.

Jürgen Purtz

---

From: Alvaro Herrera <[email-masked]>
Date: Wed, 4 May 2016 14:12:05 -0300

Jürgen Purtz wrote:

> The real challenge is the second
> step as it implies some manual modifications (entities, non-valid markup in
> sense of db5-schema) and a switch to a different output chain. Maybe we can
> live for a while with some files, which are not valid against db5-schema -
> as far as the output chain produces correct results.

Speaking of entities, I noticed you changed some entities such as
&mdash; to __mdash__ and such.  That's not acceptable.  What is
Docbook5's accepted way to enter such characters?

---

From: Alexander Law <[email-masked]>
Date: Wed, 4 May 2016 21:00:13 +0300

> can I find the optimized script or a description?
It was attached to the message: 
http://www.postgresql.org/message-id/[email-masked]
> "Divide and conquer" is a good strategy and people use it in many 
> cases. As you have stated, there are two major steps: from db4-sgml to 
> db4-xml and from there to db5-xml. In parallel to the second one we 
> shall migrate from dsl scripts to db5-xslt scripts. Your idea to go 
> step by step and stabilise at the intermediate level is good in 
> general. But in this case it may be unnecessary. The first step is 
> very small. It consists mainly of the elimination of shorttags and 
> empty elements. This is a pure formal act without risk. If we would 
> stop at this point, people are forced to switch their environment, eg 
> .emacs from db4-sgml to db4-xml - and after the second step to 
> db5-xml. This is possible - but the twice changing will bring 
> (possibly) more confusion than advantages. The real challenge is the 
> second step as it implies some manual modifications (entities, 
> non-valid markup in sense of db5-schema) and a switch to a different 
> output chain. Maybe we can live for a while with some files, which are 
> not valid against db5-schema - as far as the output chain produces 
> correct results.
By first step I mean SGML->XML conversion (while staying with DocBook4). 
It's not small, IMHO, as it involves all the doc/sgml contents replacing 
(with doc/xml or alike) and updating makefile (replacing 'html' target 
with 'xslthtml' and so on).
Though it can (and should) be performed as one commit with using one 
conversion script.
The advantage of "baby steps" for me is an opportunity to play safe.
In fact it's the question of balance between amount of redundant work 
and manageability of the conversion.
IMO, amount of redundant work is not so large as:
1) we should convert and sgml->xml anyway
2) we can use existing makefile's targets
3) we should update documentation on documentation ([1], [2]) anyway.

[1] http://www.postgresql.org/docs/9.5/interactive/docguide-build.html
[2] http://www.postgresql.org/docs/9.5/interactive/docguide-authoring.html

Alexander Lakhin

---

From: Jürgen Purtz <[email-masked]>
Date: Wed, 4 May 2016 20:06:23 +0200

Hello Alvaro,

yes, character entities respectively their values must be kept (what you 
have seen is an intermediate state). We will use utf-8, so every 
possible Unicode code point can be used directly. But we use not only 
character entities, there are also parameter entities and external 
entities. The external entities will be replaced by xi:XInclude. At last 
there are 4 parameter entities, to whom I actually have no solution: 
%standalone-ignore; %standalone-include; %include-index; 
%include-xslt-index; . But they should not be a show-stopper.

Jürgen Purtz

---

From: Jürgen Purtz <[email-masked]>
Date: Wed, 4 May 2016 20:11:45 +0200

Alvaro,

the advantage of draft mode is smaller than 15% in the three 
environments. In Docbook5 it reduces the elapsed time from 4:07 to 4:02.

Jürgen Purtz

---

From: Alvaro Herrera <[email-masked]>
Date: Wed, 4 May 2016 15:20:43 -0300

Jürgen Purtz wrote:
> have seen is an intermediate state). We will use utf-8, so every possible
> Unicode code point can be used directly. But we use not only character
> entities, there are also parameter entities and external entities. The
> external entities will be replaced by xi:XInclude.

OK.  Currently we have no non-ASCII chars in our source code, so this
would be without precedent, but I think all modern tools should cope.
The only pain point may be Tom Lane's mail client, which is unique in
still using us-ascii encoding.

> At last there are 4 parameter entities, to whom I actually have no
> solution: %standalone-ignore; %standalone-include; %include-index;

Hmm?  I think we use these entities to generate text files that are
distributed in the tarball.  How would we generate these files in the
Docbook5 XML world?

---

From: Peter Eisentraut <[email-masked]>
Date: Wed, 4 May 2016 21:09:28 -0400

> non-valid situations, you described before?

I think the process should be something like this:

- Apply your XSLT performance patch.  The patch should be submitted to 
the next commit fest.

- Wait a while to make sure everyone is happy with the performance. 
Keep tweaking if necessary.

- Port all DSSSL customizations to XSLT.  Manually evaluate output for 
quality.

- Switch to XSLT build for official HTML documentation. [milestone 1]

- Convert sources to XML. (There could be substeps here.) [milestone 2]

- Then consider upgrading to DocBook 5. [milestone 3]

---

From: Alexander Law <[email-masked]>
Date: Thu, 5 May 2016 07:45:59 +0300

Done (previous patch cleaned).
This patch optimizes XSL transformations contained in docbook-xsl (1.78.1).

Tested with 9.5.2
time make html
real    1m21.989s
user    1m21.392s
sys     0m0.484s

1) time make xslthtml
(before the patch)
real    29m19.904s
user    29m18.804s
sys     0m0.888s

2) time make xslthtml
(after the patch)
real    3m8.483s
user    3m7.556s
sys     0m0.864s

To make sure that the result of the transformation is the same:
After 1):
mv html html.xslt1
After 2):
mv html html.xslt2
for f in *.xslt*/*.html; do sed -e 
's/id=\"\(ftn\.\)\?id[a-z][0-9]\+\"/id=\"id\"/g' -i $f ; sed -e 
's/href=\"[^#]*#\(ftn\.\)\?id[a-z][0-9]\+\"/href=\"#\"/g' -i $f; done
diff -u -r html.xslt1 html.xslt2

Best regards,
Alexander

> Please make sure the patch is registered in the next commit fest.

diff --git a/doc/src/sgml/stylesheet-xhtml-speedup.xsl b/doc/src/sgml/stylesheet-xhtml-speedup.xsl
new file mode 100644
index 0000000..d52b48e
--- /dev/null
+++ b/doc/src/sgml/stylesheet-xhtml-speedup.xsl
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0"
+                xmlns="http://www.w3.org/1999/xhtml"
+                exclude-result-prefixes="#default">
+
+<!-- common/labels.xsl -->
+<xsl:template match="appendix" mode="label.markup">
+  <xsl:choose>
+    <xsl:when test="@label">
+      <xsl:value-of select="@label"/>
+    </xsl:when>
+    <xsl:when test="string($appendix.autolabel) != 0">
+      <xsl:if test="$component.label.includes.part.label != 0 and
+                      ancestor::part">
+        <xsl:variable name="part.label">
+          <xsl:apply-templates select="ancestor::part"
+                               mode="label.markup"/>
+        </xsl:variable>
+        <xsl:if test="$part.label != ''">
+          <xsl:value-of select="$part.label"/>
+          <xsl:apply-templates select="ancestor::part"
+                               mode="intralabel.punctuation"/>
+        </xsl:if>
+      </xsl:if>
+      <xsl:variable name="format">
+        <xsl:call-template name="autolabel.format">
+          <xsl:with-param name="format" select="$appendix.autolabel"/>
+        </xsl:call-template>
+      </xsl:variable>
+        <xsl:choose>
+        <xsl:when test="$label.from.part != 0 and ancestor::part">
+          <xsl:number from="part" count="appendix" format="{$format}" level="any"/>
+        </xsl:when>
+        <xsl:otherwise>
+<!-- speed optimizations for pgsql-docs -->
+          <xsl:number value="count(../preceding-sibling::part/appendix) + count(preceding-sibling::appendix) + 1" format="{$format}" />
+<!--       <xsl:number from="book|article"
+                      count="appendix" format="{$format}" level="any"/> -->
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+<!-- common/labels.xsl -->
+<xsl:template match="chapter" mode="label.markup">
+  <xsl:choose>
+    <xsl:when test="@label">
+      <xsl:value-of select="@label"/>
+    </xsl:when>
+    <xsl:when test="string($chapter.autolabel) != 0">
+      <xsl:if test="$component.label.includes.part.label != 0 and
+                      ancestor::part">
+        <xsl:variable name="part.label">
+          <xsl:apply-templates select="ancestor::part"
+                               mode="label.markup"/>
+        </xsl:variable>
+        <xsl:if test="$part.label != ''">
+          <xsl:value-of select="$part.label"/>
+          <xsl:apply-templates select="ancestor::part"
+                               mode="intralabel.punctuation"/>
+        </xsl:if>
+      </xsl:if>
+      <xsl:variable name="format">
+        <xsl:call-template name="autolabel.format">
+          <xsl:with-param name="format" select="$chapter.autolabel"/>
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="$label.from.part != 0 and ancestor::part">
+          <xsl:number from="part" count="chapter" format="{$format}" level="any"/>
+        </xsl:when>
+        <xsl:otherwise>
+<!-- speed optimizations for pgsql-docs -->
+          <xsl:number value="count(../preceding-sibling::part/chapter) + count(preceding-sibling::chapter) + 1" format="{$format}" />
+<!--          <xsl:number from="book" count="chapter" format="{$format}" level="any"/> -->
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+<!-- xhtml/autoidx.xsl -->
+<xsl:template match="indexterm" mode="reference">
+  <xsl:param name="scope" select="."/>
+  <xsl:param name="role" select="''"/>
+  <xsl:param name="type" select="''"/>
+  <xsl:param name="position"/>
+  <xsl:param name="separator" select="''"/>
+
+  <xsl:variable name="term.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.term.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:variable name="number.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.number.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:variable name="range.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.range.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:choose>
+    <xsl:when test="$separator != ''">
+      <xsl:value-of select="$separator"/>
+    </xsl:when>
+    <xsl:when test="$position = 1">
+      <xsl:value-of select="$term.separator"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="$number.separator"/>
+    </xsl:otherwise>
+  </xsl:choose>
+
+  <xsl:choose>
+    <xsl:when test="@zone and string(@zone)">
+      <xsl:call-template name="reference">
+        <xsl:with-param name="zones" select="normalize-space(@zone)"/>
+        <xsl:with-param name="position" select="position()"/>
+        <xsl:with-param name="scope" select="$scope"/>
+        <xsl:with-param name="role" select="$role"/>
+        <xsl:with-param name="type" select="$type"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:variable name="title">
+          <xsl:choose>
+            <xsl:when test="$index.prefer.titleabbrev != 0">
+              <xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="titleabbrev.markup"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="title.markup"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+
+        <xsl:attribute name="href">
+          <xsl:choose>
+            <xsl:when test="$index.links.to.section = 1">
+              <xsl:call-template name="href.target">
+                <xsl:with-param name="object" select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]"/>
+<!-- speed optimizations for pgsql-docs -->
+                <xsl:with-param name="context" select="(/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
+              </xsl:call-template>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:call-template name="href.target">
+                <xsl:with-param name="object" select="."/>
+                <xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
+              </xsl:call-template>
+            </xsl:otherwise>
+          </xsl:choose>
+
+        </xsl:attribute>
+
+        <xsl:value-of select="$title"/> <!-- text only -->
+      </a>
+
+      <xsl:variable name="id" select="(@id|@xml:id)[1]"/>
+      <xsl:if test="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))]">
+        <xsl:apply-templates select="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][last()]" mode="reference">
+          <xsl:with-param name="position" select="position()"/>
+          <xsl:with-param name="scope" select="$scope"/>
+          <xsl:with-param name="role" select="$role"/>
+          <xsl:with-param name="type" select="$type"/>
+          <xsl:with-param name="separator" select="$range.separator"/>
+        </xsl:apply-templates>
+      </xsl:if>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!-- xhtml/chunk-common.xsl -->
+<xsl:template name="chunk-all-sections">
+  <xsl:param name="content">
+    <xsl:apply-imports/>
+  </xsl:param>
+
+<!-- speed optimizations for pgsql-docs -->
+  <xsl:variable name="prev-v1" select="preceding::*[(self::sect1 and $chunk.section.depth &gt; 0) or (self::sect2 and $chunk.section.depth &gt; 1) or (self::sect3 and $chunk.section.depth &gt; 2) or (self::sect4 and $chunk.section.depth &gt; 3) or (self::sect5 and $chunk.section.depth &gt; 4)][1]"/>
+
+  <xsl:variable name="prev-v2" select="(ancestor::sect1[$chunk.section.depth &gt; 0 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |ancestor::sect2[$chunk.section.depth &gt; 1 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |ancestor::sect3[$chunk.section.depth &gt; 2 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |ancestor::sect4[$chunk.section.depth &gt; 3 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |ancestor::sect5[$chunk.section.depth &gt; 4 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |ancestor::section[$chunk.section.depth &gt; count(ancestor::section) and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1])[last()]"/>
+
+  <xsl:variable name="prev" select="(preceding::book[1]              |preceding::preface[1]              |preceding::chapter[1]              |preceding::appendix[1]              |preceding::part[1]              |preceding::reference[1]              |preceding::refentry[1]              |preceding::colophon[1]              |preceding::article[1]              |preceding::topic[1]              |preceding::bibliography[parent::article or parent::book or parent::part][1]              |preceding::glossary[parent::article or parent::book or parent::part][1]              |preceding::index[$generate.index != 0]                                [parent::article or parent::book or parent::part][1]              |preceding::setindex[$generate.index != 0][1]              |ancestor::set              |ancestor::book[1]              |ancestor::preface[1]              |ancestor::chapter[1]              |ancestor::appendix[1]              |ancestor::part[1]              |ancestor::reference[1]              |ancestor::article[1]   |ancestor::topic[1]              |$prev-v1              |$prev-v2)[last()]"/>
+
+<!-- speed optimizations for pgsql-docs -->
+  <xsl:variable name="next-v1" select="following::*[self::sect1 or self::sect2 or self::sect3 or self::sect4 or self::sect5][1]"/>
+
+  <xsl:variable name="next-v2" select="(descendant::sect1[$chunk.section.depth &gt; 0 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |descendant::sect2[$chunk.section.depth &gt; 1 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |descendant::sect3[$chunk.section.depth &gt; 2 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |descendant::sect4[$chunk.section.depth &gt; 3 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |descendant::sect5[$chunk.section.depth &gt; 4 and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1]              |descendant::section[$chunk.section.depth                                    &gt; count(ancestor::section) and not(ancestor::*/processing-instruction('dbhtml')[normalize-space(.) ='stop-chunking'])][1])[1]"/>
+
+  <xsl:variable name="next" select="(following::book[1]              |following::preface[1]              |following::chapter[1]              |following::appendix[1]              |following::part[1]              |following::reference[1]              |following::refentry[1]              |following::colophon[1]              |following::bibliography[parent::article or parent::book or parent::part][1]              |following::glossary[parent::article or parent::book or parent::part][1]              |following::index[$generate.index != 0]                                [parent::article or parent::book][1]              |following::article[1]              |following::topic[1]              |following::setindex[$generate.index != 0][1]              |descendant::book[1]              |descendant::preface[1]              |descendant::chapter[1]              |descendant::appendix[1]              |descendant::article[1]              |descendant::topic[1]              |descendant::bibliography[parent::article or parent::book][1]              |descendant::glossary[parent::article or parent::book or parent::part][1]              |descendant::index[$generate.index != 0]                                [parent::article or parent::book][1]              |descendant::colophon[1]              |descendant::setindex[$generate.index != 0][1]              |descendant::part[1]              |descendant::reference[1]              |descendant::refentry[1]              |$next-v1              |$next-v2)[1]"/>
+
+
+  <xsl:call-template name="process-chunk">
+    <xsl:with-param name="prev" select="$prev"/>
+    <xsl:with-param name="next" select="$next"/>
+    <xsl:with-param name="content" select="$content"/>
+  </xsl:call-template>
+
+</xsl:template>
+
+
+<xsl:template name="make.legalnotice.head.links">
+  <!-- * the following ID is used as part of the legalnotice filename; -->
+  <!-- * we need it in order to construct the filename for use in the -->
+  <!-- * value of the href attribute on the link -->
+
+  <xsl:param name="ln-node" select="(//legalnotice)[1]"/>
+
+  <xsl:param name="linktype">
+    <xsl:choose>
+      <xsl:when test="contains($html.head.legalnotice.link.types, ' ')">
+        <xsl:value-of select="normalize-space(                     substring-before($html.head.legalnotice.link.types, ' '))"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$html.head.legalnotice.link.types"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:param>
+  <xsl:param name="remaining.linktypes" select="concat(               normalize-space(               substring-after($html.head.legalnotice.link.types, ' ')),' ')"/>
+  <xsl:if test="not($linktype = '')">
+    <!-- Compute name of legalnotice file (see titlepage.xsl) -->
+    <xsl:variable name="file">
+      <xsl:call-template name="ln.or.rh.filename">
+    <xsl:with-param name="node" select="$ln-node"/>
+      </xsl:call-template>
+    </xsl:variable>
+
+    <link rel="{$linktype}">
+      <xsl:attribute name="href">
+        <xsl:value-of select="$file"/>
+      </xsl:attribute>
+      <xsl:attribute name="title">
+<!-- speed optimizations for pgsql-docs -->
+        <xsl:apply-templates select="/book/bookinfo/legalnotice" mode="object.title.markup.textonly"/>
+      </xsl:attribute>
+    </link>
+<!-- speed optimizations for pgsql-docs -->
+<!--    <xsl:call-template name="make.legalnotice.head.links">
+      < ! - - * pop the next value off the list of link types - - >
+      <xsl:with-param name="linktype" select="substring-before($remaining.linktypes, ' ')"/>
+      < ! - - * remove the link type from the list of remaining link types - - >
+      <xsl:with-param name="remaining.linktypes" select="substring-after($remaining.linktypes, ' ')"/>
+    </xsl:call-template> -->
+  </xsl:if>
+</xsl:template>
+
+<!-- xhtml/html.xsl (needed for the following "reference" template) -->
+<xsl:template name="id.attribute">
+  <xsl:param name="node" select="."/>
+  <xsl:param name="conditional" select="1"/>
+  <xsl:choose>
+    <xsl:when test="$generate.id.attributes = 0">
+      <!-- No id attributes when this param is zero -->
+    </xsl:when>
+    <xsl:when test="$conditional = 0 or $node/@id or $node/@xml:id">
+      <xsl:attribute name="id">
+        <xsl:call-template name="object.id">
+          <xsl:with-param name="object" select="$node"/>
+        </xsl:call-template>
+      </xsl:attribute>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+<!-- xhtml/autoidx.xsl -->
+<xsl:template name="reference">
+  <xsl:param name="scope" select="."/>
+  <xsl:param name="role" select="''"/>
+  <xsl:param name="type" select="''"/>
+  <xsl:param name="zones"/>
+
+  <xsl:choose>
+    <xsl:when test="contains($zones, ' ')">
+      <xsl:variable name="zone" select="substring-before($zones, ' ')"/>
+      <xsl:variable name="target" select="key('sections', $zone)"/>
+
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:call-template name="id.attribute"/>
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$target[1]"/>
+            <xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:apply-templates select="$target[1]" mode="index-title-content"/>
+      </a>
+      <xsl:text>, </xsl:text>
+      <xsl:call-template name="reference">
+        <xsl:with-param name="zones" select="substring-after($zones, ' ')"/>
+        <xsl:with-param name="position" select="position()"/>
+        <xsl:with-param name="scope" select="$scope"/>
+        <xsl:with-param name="role" select="$role"/>
+        <xsl:with-param name="type" select="$type"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:variable name="zone" select="$zones"/>
+      <xsl:variable name="target" select="key('sections', $zone)"/>
+
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:call-template name="id.attribute"/>
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$target[1]"/>
+<!-- speed optimizations for pgsql-docs -->
+            <xsl:with-param name="context" select="/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:apply-templates select="$target[1]" mode="index-title-content"/>
+      </a>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet.xsl b/doc/src/sgml/stylesheet.xsl
index 7967b36..8b01f41 100644
--- a/doc/src/sgml/stylesheet.xsl
+++ b/doc/src/sgml/stylesheet.xsl
@@ -6,6 +6,7 @@
 
 <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
 <xsl:include href="stylesheet-common.xsl" />
+<xsl:include href="stylesheet-xhtml-speedup.xsl" />

 <!-- Parameters -->

---

From: Alexander Law <[email-masked]>
Date: Thu, 5 May 2016 07:55:00 +0300

Hello Peter,
I fully support your plan  and going to move this way.

Best regards,
Alexander

---

From: Jürgen Purtz <[email-masked]>
Date: Thu, 12 May 2016 21:46:11 +0200

Hi,

after some manual interventions (which must become part of an algorithm) 
it's possible to created the complete PDF file for the db4 production 
chain: *.sgml -- (perl) --> *.xml and after that step: postgres.xml -- 
(evaluate XInclude with xmllint) --> postgres_all.xml -- (xsltproc using 
standard db4 stylesheet) --> postgres_all.fo -- (fop) --> 
postgres_all.pdf. The fo/pdf generation takes about 1 minute.

Actually the layout of the resulting pdf file differs from the original 
one as I used only standard scripts without any adoption to the 
PostgreSQL styles. Additionally I'm missing some of the links.

Jürgen Purtz

On 04.05.2016 17:30, Jürgen Purtz wrote:
> to convert the complete 'postgres_all.xml' file, fop crashes after 
> some minutes. As fop is a Java application, it is possible that the 
> assigned main memory is short (-Xms -Xmx, ...) - or it comes from some 
> other Java specific issues. I will work on this in the next days.
>
> Jürgen Purtz
>

---

From: Alvaro Herrera <[email-masked]>
Date: Thu, 12 May 2016 16:59:55 -0300

Jürgen Purtz wrote:

> it's possible to created the complete PDF file for the db4 production chain:
> *.sgml -- (perl) --> *.xml and after that step: postgres.xml -- (evaluate
> XInclude with xmllint) --> postgres_all.xml -- (xsltproc using standard db4
> stylesheet) --> postgres_all.fo -- (fop) --> postgres_all.pdf. The fo/pdf
> generation takes about 1 minute.

Uh?  So generating the PDF is much quicker than generating the HTML?
That's strange, but if true, then I'm happy about it.

> Actually the layout of the resulting pdf file differs from the original one
> as I used only standard scripts without any adoption to the PostgreSQL
> styles.

Surely this can be sorted out.

> Additionally I'm missing some of the links.

Not sure what you mean here.

Did you figure a way to generate the INSTALL file?

---

From: Jürgen Purtz <[email-masked]>
Date: Fri, 13 May 2016 09:38:04 +0200

Is everybody happy with the performance patch?
Is anybody working on the DSSSL --> XSLT conversion? We should avoid 
parallel work.

Jürgen Purtz

---

From: Peter Eisentraut <[email-masked]>
Date: Fri, 13 May 2016 14:01:23 -0400

> Is anybody working on the DSSSL --> XSLT conversion? We should avoid

The performance patch is in the next commit fest for review.

The DSSSL -> XSLT conversion basically just needs someone to go through 
the existing code and output and identify necessary improvements.

Most people right now are working on getting the current release out, so 
I don't expect much to happen here for a while.

---

From: Alexander Law <[email-masked]>
Date: Sat, 14 May 2016 09:34:59 +0300

Hello Jürgen,

We started to work on the conversion:
http://www.postgresql.org/message-id/[email-masked]
And now we (at PostgresPro) are going to continue this work.
I think we should do it together to avoid redundant work.

Best regards,
Alexander

13.05.2016 21:01, Peter Eisentraut пишет:
> The DSSSL -> XSLT conversion basically just needs someone to go 
> through the existing code and output and identify necessary improvements.
>
> Most people right now are working on getting the current release out, 
> so I don't expect much to happen here for a while.
>

---

From: Jürgen Purtz <[email-masked]>
Date: Sun, 22 May 2016 21:48:11 +0200

We maintain two css files: docs.css (for online, complex) and 
stylesheet.css (local, simple). Why do we need stylesheet.css? Because 
of the references to some png-files in docs.css? Because of Lynx? For of 
easier comparisons?

Kind regards, Jürgen Purtz

---

From: Peter Eisentraut <[email-masked]>
Date: Tue, 31 May 2016 13:46:47 -0400

On 5/22/16 3:48 PM, Jürgen Purtz wrote:
> stylesheet.css (local, simple). Why do we need stylesheet.css?

So you can read the documentation locally without referencing online files.

---

From: Peter Eisentraut <[email-masked]>
Date: Fri, 3 Jun 2016 15:31:31 -0400

> This patch optimizes XSL transformations contained in docbook-xsl (1.78.1).

I have looked through this patch, and it's awesome.  I have tweaked it a 
bit more along the lines you guys have started, and now the build time 
is pretty much the same as with DSSSL.  Attached is my final patch, 
which I plan to commit as soon as the new branch opens.

(I only have Alexander Lakhin as credit right now.  Please let me know 
if anyone else contributed.)

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From bc7fc7693e3a054ab6e46c3dc931c1d2535f2b40 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Fri, 3 Jun 2016 14:47:38 -0400
Subject: [PATCH] doc: Speed up XSLT builds

The upstream XSLT stylesheets use some very general XPath expressions in
some places that end up being very slow.  We can optimize them with
knowledge about the DocBook document structure and our particular use
thereof.  For example, when counting preceding chapters to get a number
for the current chapter, we only need to count preceding sibling
nodes (more or less) instead of searching through the entire node tree
for chapter elements.

This change attacks the slowest pieces as identified by xsltproc
--profile.  This makes the HTML build roughly 10 times faster, resulting
in the new total build time being about the same as the old DSSSL-based
build.  Some of the non-HTML build targets (especially FO) will also
benefit a bit, but they have not been specifically analyzed.

With this, also remove the pg.fast parameter, which was previously a
hack to get the build to a manageable speed.

Alexander Lakhin <[email-masked]>, with some additional
tweaking by me
---
 doc/src/sgml/stylesheet-common.xsl         |   8 +-
 doc/src/sgml/stylesheet-speedup-common.xsl |  94 +++++++++
 doc/src/sgml/stylesheet-speedup-xhtml.xsl  | 293 +++++++++++++++++++++++++++++
 doc/src/sgml/stylesheet.xsl                |   1 +
 4 files changed, 391 insertions(+), 5 deletions(-)
 create mode 100644 doc/src/sgml/stylesheet-speedup-common.xsl
 create mode 100644 doc/src/sgml/stylesheet-speedup-xhtml.xsl

diff --git a/doc/src/sgml/stylesheet-common.xsl b/doc/src/sgml/stylesheet-common.xsl
index de36376..e384113 100644
--- a/doc/src/sgml/stylesheet-common.xsl
+++ b/doc/src/sgml/stylesheet-common.xsl
@@ -7,11 +7,10 @@
   all output formats (HTML, HTML Help, XSL-FO, etc.).
   -->
 
+<xsl:include href="stylesheet-speedup-common.xsl" />
 
 <!-- Parameters -->
 
-<xsl:param name="pg.fast" select="'0'"/>
-
 <!--
 <xsl:param name="draft.mode">
   <xsl:choose>
@@ -31,9 +30,8 @@
 <xsl:param name="callout.graphics" select="'0'"></xsl:param>
 <xsl:param name="toc.section.depth">2</xsl:param>
 <xsl:param name="linenumbering.extension" select="'0'"></xsl:param>
-<xsl:param name="generate.index" select="1 - $pg.fast"></xsl:param>
-<xsl:param name="section.autolabel" select="1 - $pg.fast"></xsl:param>
-<xsl:param name="section.label.includes.component.label" select="1 - $pg.fast"></xsl:param>
+<xsl:param name="section.autolabel" select="1"></xsl:param>
+<xsl:param name="section.label.includes.component.label" select="1"></xsl:param>
 <xsl:param name="refentry.xref.manvolnum" select="0"/>
 <xsl:param name="formal.procedures" select="0"></xsl:param>
 <xsl:param name="punct.honorific" select="''"></xsl:param>
diff --git a/doc/src/sgml/stylesheet-speedup-common.xsl b/doc/src/sgml/stylesheet-speedup-common.xsl
new file mode 100644
index 0000000..007fdf6
--- /dev/null
+++ b/doc/src/sgml/stylesheet-speedup-common.xsl
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version='1.0'>
+
+<!-- Performance-optimized versions of some upstream templates from common/
+     directory -->
+
+<!-- from common/labels.xsl -->
+
+<xsl:template match="chapter" mode="label.markup">
+  <xsl:choose>
+    <xsl:when test="@label">
+      <xsl:value-of select="@label"/>
+    </xsl:when>
+    <xsl:when test="string($chapter.autolabel) != 0">
+      <xsl:if test="$component.label.includes.part.label != 0 and
+                      ancestor::part">
+        <xsl:variable name="part.label">
+          <xsl:apply-templates select="ancestor::part"
+                               mode="label.markup"/>
+        </xsl:variable>
+        <xsl:if test="$part.label != ''">
+          <xsl:value-of select="$part.label"/>
+          <xsl:apply-templates select="ancestor::part"
+                               mode="intralabel.punctuation">
+            <xsl:with-param name="object" select="."/>
+          </xsl:apply-templates>
+        </xsl:if>
+      </xsl:if>
+      <xsl:variable name="format">
+        <xsl:call-template name="autolabel.format">
+          <xsl:with-param name="format" select="$chapter.autolabel"/>
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="$label.from.part != 0 and ancestor::part">
+          <xsl:number from="part" count="chapter" format="{$format}" level="any"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <!-- Optimization for pgsql-docs: When counting to get label for
+               this chapter, preceding chapters can only be our siblings or
+               children of a preceding part, so only count those instead of
+               scanning the entire node tree. -->
+          <!-- <xsl:number from="book" count="chapter" format="{$format}" level="any"/> -->
+          <xsl:number value="count(../preceding-sibling::part/chapter) + count(preceding-sibling::chapter) + 1" format="{$format}"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="appendix" mode="label.markup">
+  <xsl:choose>
+    <xsl:when test="@label">
+      <xsl:value-of select="@label"/>
+    </xsl:when>
+    <xsl:when test="string($appendix.autolabel) != 0">
+      <xsl:if test="$component.label.includes.part.label != 0 and
+                      ancestor::part">
+        <xsl:variable name="part.label">
+          <xsl:apply-templates select="ancestor::part"
+                               mode="label.markup"/>
+        </xsl:variable>
+        <xsl:if test="$part.label != ''">
+          <xsl:value-of select="$part.label"/>
+          <xsl:apply-templates select="ancestor::part"
+                               mode="intralabel.punctuation">
+            <xsl:with-param name="object" select="."/>
+          </xsl:apply-templates>
+        </xsl:if>
+      </xsl:if>
+      <xsl:variable name="format">
+        <xsl:call-template name="autolabel.format">
+          <xsl:with-param name="format" select="$appendix.autolabel"/>
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="$label.from.part != 0 and ancestor::part">
+          <xsl:number from="part" count="appendix" format="{$format}" level="any"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <!-- Optimization for pgsql-docs: When counting to get label for
+               this appendix, preceding appendixes can only be our siblings or
+               children of a preceding part, so only count those instead of
+               scanning the entire node tree. -->
+          <!-- <xsl:number from="book|article" count="appendix" format="{$format}" level="any"/> -->
+          <xsl:number value="count(../preceding-sibling::part/appendix) + count(preceding-sibling::appendix) + 1" format="{$format}"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet-speedup-xhtml.xsl b/doc/src/sgml/stylesheet-speedup-xhtml.xsl
new file mode 100644
index 0000000..7c391a0
--- /dev/null
+++ b/doc/src/sgml/stylesheet-speedup-xhtml.xsl
@@ -0,0 +1,293 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns="http://www.w3.org/1999/xhtml"
+                version='1.0'>
+
+<!-- Performance-optimized versions of some upstream templates from xhtml/
+     directory -->
+
+<!-- from xhtml/autoidx.xsl -->
+
+<xsl:template match="indexterm" mode="reference">
+  <xsl:param name="scope" select="."/>
+  <xsl:param name="role" select="''"/>
+  <xsl:param name="type" select="''"/>
+  <xsl:param name="position"/>
+  <xsl:param name="separator" select="''"/>
+
+  <xsl:variable name="term.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.term.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:variable name="number.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.number.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:variable name="range.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.range.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:choose>
+    <xsl:when test="$separator != ''">
+      <xsl:value-of select="$separator"/>
+    </xsl:when>
+    <xsl:when test="$position = 1">
+      <xsl:value-of select="$term.separator"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="$number.separator"/>
+    </xsl:otherwise>
+  </xsl:choose>
+
+  <xsl:choose>
+    <xsl:when test="@zone and string(@zone)">
+      <xsl:call-template name="reference">
+        <xsl:with-param name="zones" select="normalize-space(@zone)"/>
+        <xsl:with-param name="position" select="position()"/>
+        <xsl:with-param name="scope" select="$scope"/>
+        <xsl:with-param name="role" select="$role"/>
+        <xsl:with-param name="type" select="$type"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:variable name="title">
+          <xsl:choose>
+            <xsl:when test="$index.prefer.titleabbrev != 0">
+              <xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="titleabbrev.markup"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="title.markup"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+
+        <xsl:attribute name="href">
+          <xsl:choose>
+            <xsl:when test="$index.links.to.section = 1">
+              <xsl:call-template name="href.target">
+                <xsl:with-param name="object" select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]"/>
+                <!-- Optimization for pgsql-docs: We only have an index as a
+                     child of book, so look that up directly instead of
+                     scanning the entire node tree.  Also, don't look for
+                     setindex. -->
+                <!-- <xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/> -->
+                <xsl:with-param name="context" select="(/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
+              </xsl:call-template>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:call-template name="href.target">
+                <xsl:with-param name="object" select="."/>
+                <xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
+              </xsl:call-template>
+            </xsl:otherwise>
+          </xsl:choose>
+
+        </xsl:attribute>
+
+        <xsl:value-of select="$title"/> <!-- text only -->
+      </a>
+
+      <xsl:variable name="id" select="(@id|@xml:id)[1]"/>
+      <xsl:if test="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))]">
+        <xsl:apply-templates select="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][last()]" mode="reference">
+          <xsl:with-param name="position" select="position()"/>
+          <xsl:with-param name="scope" select="$scope"/>
+          <xsl:with-param name="role" select="$role"/>
+          <xsl:with-param name="type" select="$type"/>
+          <xsl:with-param name="separator" select="$range.separator"/>
+        </xsl:apply-templates>
+      </xsl:if>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template name="reference">
+  <xsl:param name="scope" select="."/>
+  <xsl:param name="role" select="''"/>
+  <xsl:param name="type" select="''"/>
+  <xsl:param name="zones"/>
+
+  <xsl:choose>
+    <xsl:when test="contains($zones, ' ')">
+      <xsl:variable name="zone" select="substring-before($zones, ' ')"/>
+      <xsl:variable name="target" select="key('sections', $zone)"/>
+
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:call-template name="id.attribute"/>
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$target[1]"/>
+            <xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:apply-templates select="$target[1]" mode="index-title-content"/>
+      </a>
+      <xsl:text>, </xsl:text>
+      <xsl:call-template name="reference">
+        <xsl:with-param name="zones" select="substring-after($zones, ' ')"/>
+        <xsl:with-param name="position" select="position()"/>
+        <xsl:with-param name="scope" select="$scope"/>
+        <xsl:with-param name="role" select="$role"/>
+        <xsl:with-param name="type" select="$type"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:variable name="zone" select="$zones"/>
+      <xsl:variable name="target" select="key('sections', $zone)"/>
+
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:call-template name="id.attribute"/>
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$target[1]"/>
+            <!-- Optimization for pgsql-docs: Only look for index under book
+                 instead of searching the whole node tree. -->
+            <!-- <xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/> -->
+            <xsl:with-param name="context" select="/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:apply-templates select="$target[1]" mode="index-title-content"/>
+      </a>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+
+<!-- from xhtml/chunk-common.xsl -->
+
+<xsl:template name="chunk-all-sections">
+  <xsl:param name="content">
+    <xsl:apply-imports/>
+  </xsl:param>
+
+  <!-- Optimization for pgsql-docs: Since we set a fixed $chunk.section.depth,
+       we can do away with a bunch of complicated XPath searches for the
+       previous and next sections at various levels. -->
+
+  <xsl:if test="$chunk.section.depth != 1">
+    <xsl:message terminate="yes">
+      <xsl:text>Error: If you change $chunk.section.depth, then you must update the performance-optimized chunk-all-sections-template.</xsl:text>
+    </xsl:message>
+  </xsl:if>
+
+  <xsl:variable name="prev"
+    select="(preceding::book[1]
+             |preceding::preface[1]
+             |preceding::chapter[1]
+             |preceding::appendix[1]
+             |preceding::part[1]
+             |preceding::reference[1]
+             |preceding::refentry[1]
+             |preceding::colophon[1]
+             |preceding::article[1]
+             |preceding::topic[1]
+             |preceding::bibliography[parent::article or parent::book or parent::part][1]
+             |preceding::glossary[parent::article or parent::book or parent::part][1]
+             |preceding::index[$generate.index != 0]
+                               [parent::article or parent::book or parent::part][1]
+             |preceding::setindex[$generate.index != 0][1]
+             |ancestor::set
+             |ancestor::book[1]
+             |ancestor::preface[1]
+             |ancestor::chapter[1]
+             |ancestor::appendix[1]
+             |ancestor::part[1]
+             |ancestor::reference[1]
+             |ancestor::article[1]
+             |ancestor::topic[1]
+             |preceding::sect1[1]
+             |ancestor::sect1[1])[last()]"/>
+
+  <xsl:variable name="next"
+    select="(following::book[1]
+             |following::preface[1]
+             |following::chapter[1]
+             |following::appendix[1]
+             |following::part[1]
+             |following::reference[1]
+             |following::refentry[1]
+             |following::colophon[1]
+             |following::bibliography[parent::article or parent::book or parent::part][1]
+             |following::glossary[parent::article or parent::book or parent::part][1]
+             |following::index[$generate.index != 0]
+                               [parent::article or parent::book][1]
+             |following::article[1]
+             |following::topic[1]
+             |following::setindex[$generate.index != 0][1]
+             |descendant::book[1]
+             |descendant::preface[1]
+             |descendant::chapter[1]
+             |descendant::appendix[1]
+             |descendant::article[1]
+             |descendant::topic[1]
+             |descendant::bibliography[parent::article or parent::book][1]
+             |descendant::glossary[parent::article or parent::book or parent::part][1]
+             |descendant::index[$generate.index != 0]
+                                [parent::article or parent::book][1]
+             |descendant::colophon[1]
+             |descendant::setindex[$generate.index != 0][1]
+             |descendant::part[1]
+             |descendant::reference[1]
+             |descendant::refentry[1]
+             |following::sect1[1]
+             |descendant::sect1[1])[1]"/>
+
+  <xsl:call-template name="process-chunk">
+    <xsl:with-param name="prev" select="$prev"/>
+    <xsl:with-param name="next" select="$next"/>
+    <xsl:with-param name="content" select="$content"/>
+  </xsl:call-template>
+</xsl:template>
+
+<xsl:template name="html.head">
+  <xsl:param name="prev" select="/foo"/>
+  <xsl:param name="next" select="/foo"/>
+
+  <!-- Optimization for pgsql-docs: Cut out a bunch of things we don't need
+       here, including an expensive //legalnotice search. -->
+
+  <head>
+    <xsl:call-template name="system.head.content"/>
+    <xsl:call-template name="head.content"/>
+
+    <xsl:if test="$prev">
+      <link rel="prev">
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$prev"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:attribute name="title">
+          <xsl:apply-templates select="$prev" mode="object.title.markup.textonly"/>
+        </xsl:attribute>
+      </link>
+    </xsl:if>
+
+    <xsl:if test="$next">
+      <link rel="next">
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$next"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:attribute name="title">
+          <xsl:apply-templates select="$next" mode="object.title.markup.textonly"/>
+        </xsl:attribute>
+      </link>
+    </xsl:if>
+
+    <xsl:call-template name="user.head.content"/>
+  </head>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet.xsl b/doc/src/sgml/stylesheet.xsl
index 7967b36..631fcc4 100644
--- a/doc/src/sgml/stylesheet.xsl
+++ b/doc/src/sgml/stylesheet.xsl
@@ -6,6 +6,7 @@
 
 <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
 <xsl:include href="stylesheet-common.xsl" />
+<xsl:include href="stylesheet-speedup-xhtml.xsl" />

 <!-- Parameters -->
-- 
2.8.3

---

From: Alexander Law <[email-masked]>
Date: Sat, 4 Jun 2016 17:28:41 +0300

Hello Peter,

Thanks for improvements!
I checked outputs (with the attached script) and found that there is 
small difference with the improved patch.
For example, look at xtypes.html:

- <link rel="home" href="index.html" title="PostgreSQL 9.6beta1 
Documentation" /><link rel="up" href="extend.html" 
title="Chapter 35. Extending SQL" /><link rel="prev" href="xaggr.html" 
title="35.10. User-defined Aggregates" /><link rel="next" 
href="xoper.html" title="35.12. User-defined Operators" /><link 
rel="copyright" href="legalnotice.html" title="Legal Notice" /></head>

+ <link rel="prev" href="xaggr.html" title="35.10. User-defined 
Aggregates" /><link rel="next" href="xoper.html" 
title="35.12. User-defined Operators" /></head>

It caused by <xsl:template name="html.head">.
Leaving aside the question whether the links "home", "up" and 
"copyright" are needed, maybe it's better to split the commit to two?
First to speed up the conversion while making sure that the output is 
the same, and the second to change the html.head output format.

Best regards,
Alexander

03.06.2016 22:31, Peter Eisentraut пишет:
> I have looked through this patch, and it's awesome.  I have tweaked it 
> a bit more along the lines you guys have started, and now the build 
> time is pretty much the same as with DSSSL. Attached is my final 
> patch, which I plan to commit as soon as the new branch opens.
>

---

From: Peter Eisentraut <[email-masked]>
Date: Mon, 6 Jun 2016 08:28:39 -0400

> the same, and the second to change the html.head output format.

I did that intentionally, but I agree that it might be better to split 
this off into a separate commit.

---

From: Alexander Law <[email-masked]>
Date: Mon, 6 Jun 2016 20:49:38 +0300

Hello Peter,

In that case can we postpone the second commit until step 3 in your plan 
of migration to XML is done?
I mean "- Port all DSSSL customizations to XSLT.  Manually evaluate 
output for quality. ";
If we will not change contents/formatting until migration to xslt is 
done, we can ensure that output is the same by automatic means.
(See my letter: 
https://www.postgresql.org/message-id/56337365.2080104%40postgrespro.ru)

Best regards,
Alexander

---

From: Peter Eisentraut <[email-masked]>
Date: Mon, 6 Jun 2016 15:56:01 -0400

> I mean "- Port all DSSSL customizations to XSLT.  Manually evaluate

It is part of the performance work.

---

From: Jürgen Purtz <[email-masked]>
Date: Sun, 19 Jun 2016 22:22:56 +0200

> - Then consider upgrading to DocBook 5. [milestone 3] 

Alexander and I continue to work on this path. In the meanwhile we have 
reached a state where xml files are well formed and valid against 
docbook 4 dtd - each single file as well as the big postgres_all.xml 
file. Thanks to Alexander's performance patch all XSLT processes run 
very fast (the slowest is fo+pdf with 6:30 min).

On this basis I actually work on the HTML generation. But in opposite to 
the previous steps (where we create identical copies of the sgml files) 
the new css file is very different from the old one. This results from 
the following:

  * The XSLT process generates other HTML elements and other classes in
    comparison to the dsssl process.
  * XML files are case sensitive. All object names (id, ulink, linkend,
    zone, ...) are now lower case.
  * Sometimes the order of elements changed.
  * As the previous css file was constructed (some years ago) from three
    different css files, he contains redundant and sometimes
    contradictory information. I did a complete review.

To get a feedback from the community I have published the resulting 
postgres_all.html and its pgdoc_online.css file. Please refer to 
https://github.com/JuergenPurtz/pgdoc_db5/blob/master/postgresql-9.5.3/doc/src/db4_xml/postgres_all.html 
respective pgdoc_online.css to get the files. Please compare the html 
file with pages you are familiar with. And remember: the look-and-feel 
is similar, but far from identical.

Jürgen Purtz

---

From: Alexander Law <[email-masked]>
Date: Mon, 27 Jun 2016 16:21:12 +0300

Hello,

I have some progress with the "Port all DSSSL customizations to XSLT" 
step. I still think that we should avoid manual comparison of old and 
new outputs when we can align them and have all differences observable, 
countable and manageable.
I had developed XSLT's that allows us to do it. Please look at the patch 
(with all the XSLT's)  and the comparison script attached.
(There are a several dozens of changes in XSLTs and some in the script. 
Some differences still remain but they are observable and can be 
eliminated too)

Btw, can I hope to get some feedback on my previous letter regarding 
error fixes 
(https://www.postgresql.org/message-id/5736C475.3030405%40gmail.com)?

Best regards,
Alexander

19.06.2016 23:22, Jürgen Purtz пишет:
>> - Apply your XSLT performance patch.  The patch should be submitted 
>> to the next commit fest.
>>
>> - Port all DSSSL customizations to XSLT.  Manually evaluate output 
>> for quality.
>>
> Alexander and I continue to work on this path. In the meanwhile we 
> have reached a state where xml files are well formed and valid against 
> On this basis I actually work on the HTML generation. But in opposite 
> to the previous steps (where we create identical copies of the sgml 
> files) the new css file is very different from the old one. This 
> results from the following:
>
>   * The XSLT process generates other HTML elements and other classes
>     in comparison to the dsssl process.
>   * XML files are case sensitive. All object names (id, ulink,
>     linkend, zone, ...) are now lower case.
>   * As the previous css file was constructed (some years ago) from
>     three different css files, he contains redundant and sometimes

index de36376..adc82c1 100644
@@ -7,6 +7,7 @@

 <!-- Parameters -->
 
diff --git a/doc/src/sgml/stylesheet-speedup-common.xsl b/doc/src/sgml/stylesheet-speedup-common.xsl
new file mode 100644
index 0000000..007fdf6
--- /dev/null
+++ b/doc/src/sgml/stylesheet-speedup-common.xsl
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version='1.0'>
+
+<!-- Performance-optimized versions of some upstream templates from common/
+     directory -->
+
+<!-- from common/labels.xsl -->
+
+<xsl:template match="chapter" mode="label.markup">
+  <xsl:choose>
+    <xsl:when test="@label">
+      <xsl:value-of select="@label"/>
+    </xsl:when>
+    <xsl:when test="string($chapter.autolabel) != 0">
+      <xsl:if test="$component.label.includes.part.label != 0 and
+                      ancestor::part">
+        <xsl:variable name="part.label">
+          <xsl:apply-templates select="ancestor::part"
+                               mode="label.markup"/>
+        </xsl:variable>
+        <xsl:if test="$part.label != ''">
+          <xsl:value-of select="$part.label"/>
+          <xsl:apply-templates select="ancestor::part"
+                               mode="intralabel.punctuation">
+            <xsl:with-param name="object" select="."/>
+          </xsl:apply-templates>
+        </xsl:if>
+      </xsl:if>
+      <xsl:variable name="format">
+        <xsl:call-template name="autolabel.format">
+          <xsl:with-param name="format" select="$chapter.autolabel"/>
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="$label.from.part != 0 and ancestor::part">
+          <xsl:number from="part" count="chapter" format="{$format}" level="any"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <!-- Optimization for pgsql-docs: When counting to get label for
+               this chapter, preceding chapters can only be our siblings or
+               children of a preceding part, so only count those instead of
+               scanning the entire node tree. -->
+          <!-- <xsl:number from="book" count="chapter" format="{$format}" level="any"/> -->
+          <xsl:number value="count(../preceding-sibling::part/chapter) + count(preceding-sibling::chapter) + 1" format="{$format}"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="appendix" mode="label.markup">
+  <xsl:choose>
+    <xsl:when test="@label">
+      <xsl:value-of select="@label"/>
+    </xsl:when>
+    <xsl:when test="string($appendix.autolabel) != 0">
+      <xsl:if test="$component.label.includes.part.label != 0 and
+                      ancestor::part">
+        <xsl:variable name="part.label">
+          <xsl:apply-templates select="ancestor::part"
+                               mode="label.markup"/>
+        </xsl:variable>
+        <xsl:if test="$part.label != ''">
+          <xsl:value-of select="$part.label"/>
+          <xsl:apply-templates select="ancestor::part"
+                               mode="intralabel.punctuation">
+            <xsl:with-param name="object" select="."/>
+          </xsl:apply-templates>
+        </xsl:if>
+      </xsl:if>
+      <xsl:variable name="format">
+        <xsl:call-template name="autolabel.format">
+          <xsl:with-param name="format" select="$appendix.autolabel"/>
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="$label.from.part != 0 and ancestor::part">
+          <xsl:number from="part" count="appendix" format="{$format}" level="any"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <!-- Optimization for pgsql-docs: When counting to get label for
+               this appendix, preceding appendixes can only be our siblings or
+               children of a preceding part, so only count those instead of
+               scanning the entire node tree. -->
+          <!-- <xsl:number from="book|article" count="appendix" format="{$format}" level="any"/> -->
+          <xsl:number value="count(../preceding-sibling::part/appendix) + count(preceding-sibling::appendix) + 1" format="{$format}"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet-speedup-xhtml.xsl b/doc/src/sgml/stylesheet-speedup-xhtml.xsl
new file mode 100644
index 0000000..c91741d
--- /dev/null
+++ b/doc/src/sgml/stylesheet-speedup-xhtml.xsl
@@ -0,0 +1,293 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns="http://www.w3.org/1999/xhtml"
+                version='1.0'>
+
+<!-- Performance-optimized versions of some upstream templates from xhtml/
+     directory -->
+
+<!-- from xhtml/autoidx.xsl -->
+
+<xsl:template match="indexterm" mode="reference">
+  <xsl:param name="scope" select="."/>
+  <xsl:param name="role" select="''"/>
+  <xsl:param name="type" select="''"/>
+  <xsl:param name="position"/>
+  <xsl:param name="separator" select="''"/>
+
+  <xsl:variable name="term.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.term.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:variable name="number.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.number.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:variable name="range.separator">
+    <xsl:call-template name="index.separator">
+      <xsl:with-param name="key" select="'index.range.separator'"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:choose>
+    <xsl:when test="$separator != ''">
+      <xsl:value-of select="$separator"/>
+    </xsl:when>
+    <xsl:when test="$position = 1">
+      <xsl:value-of select="$term.separator"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="$number.separator"/>
+    </xsl:otherwise>
+  </xsl:choose>
+
+  <xsl:choose>
+    <xsl:when test="@zone and string(@zone)">
+      <xsl:call-template name="reference">
+        <xsl:with-param name="zones" select="normalize-space(@zone)"/>
+        <xsl:with-param name="position" select="position()"/>
+        <xsl:with-param name="scope" select="$scope"/>
+        <xsl:with-param name="role" select="$role"/>
+        <xsl:with-param name="type" select="$type"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:variable name="title">
+          <xsl:choose>
+            <xsl:when test="$index.prefer.titleabbrev != 0">
+              <xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="titleabbrev.markup"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="title.markup"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+
+        <xsl:attribute name="href">
+          <xsl:choose>
+            <xsl:when test="$index.links.to.section = 1">
+              <xsl:call-template name="href.target">
+                <xsl:with-param name="object" select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]"/>
+                <!-- Optimization for pgsql-docs: We only have an index as a
+                     child of book, so look that up directly instead of
+                     scanning the entire node tree.  Also, don't look for
+                     setindex. -->
+                <!-- <xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/> -->
+                <xsl:with-param name="context" select="(/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
+              </xsl:call-template>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:call-template name="href.target">
+                <xsl:with-param name="object" select="."/>
+                <xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
+              </xsl:call-template>
+            </xsl:otherwise>
+          </xsl:choose>
+
+        </xsl:attribute>
+
+        <xsl:value-of select="$title"/> <!-- text only -->
+      </a>
+
+      <xsl:variable name="id" select="(@id|@xml:id)[1]"/>
+      <xsl:if test="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))]">
+        <xsl:apply-templates select="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][last()]" mode="reference">
+          <xsl:with-param name="position" select="position()"/>
+          <xsl:with-param name="scope" select="$scope"/>
+          <xsl:with-param name="role" select="$role"/>
+          <xsl:with-param name="type" select="$type"/>
+          <xsl:with-param name="separator" select="$range.separator"/>
+        </xsl:apply-templates>
+      </xsl:if>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template name="reference">
+  <xsl:param name="scope" select="."/>
+  <xsl:param name="role" select="''"/>
+  <xsl:param name="type" select="''"/>
+  <xsl:param name="zones"/>
+
+  <xsl:choose>
+    <xsl:when test="contains($zones, ' ')">
+      <xsl:variable name="zone" select="substring-before($zones, ' ')"/>
+      <xsl:variable name="target" select="key('sections', $zone)"/>
+
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:call-template name="id.attribute"/>
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$target[1]"/>
+            <xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:apply-templates select="$target[1]" mode="index-title-content"/>
+      </a>
+      <xsl:text>, </xsl:text>
+      <xsl:call-template name="reference">
+        <xsl:with-param name="zones" select="substring-after($zones, ' ')"/>
+        <xsl:with-param name="position" select="position()"/>
+        <xsl:with-param name="scope" select="$scope"/>
+        <xsl:with-param name="role" select="$role"/>
+        <xsl:with-param name="type" select="$type"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:variable name="zone" select="$zones"/>
+      <xsl:variable name="target" select="key('sections', $zone)"/>
+
+      <a>
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <xsl:call-template name="id.attribute"/>
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$target[1]"/>
+            <!-- Optimization for pgsql-docs: Only look for index under book
+                 instead of searching the whole node tree. -->
+            <!-- <xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/> -->
+            <xsl:with-param name="context" select="/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:apply-templates select="$target[1]" mode="index-title-content"/>
+      </a>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+
+<!-- from xhtml/chunk-common.xsl -->
+
+<xsl:template name="chunk-all-sections">
+  <xsl:param name="content">
+    <xsl:apply-imports/>
+  </xsl:param>
+
+  <!-- Optimization for pgsql-docs: Since we set a fixed $chunk.section.depth,
+       we can do away with a bunch of complicated XPath searches for the
+       previous and next sections at various levels. -->
+
+  <xsl:if test="$chunk.section.depth != 1">
+    <xsl:message terminate="yes">
+      <xsl:text>Error: If you change $chunk.section.depth, then you must update the performance-optimized chunk-all-sections-template.</xsl:text>
+    </xsl:message>
+  </xsl:if>
+
+  <xsl:variable name="prev"
+    select="(preceding::book[1]
+             |preceding::preface[1]
+             |preceding::chapter[1]
+             |preceding::appendix[1]
+             |preceding::part[1]
+             |preceding::reference[1]
+             |preceding::refentry[1]
+             |preceding::colophon[1]
+             |preceding::article[1]
+             |preceding::topic[1]
+             |preceding::bibliography[parent::article or parent::book or parent::part][1]
+             |preceding::glossary[parent::article or parent::book or parent::part][1]
+             |preceding::index[$generate.index != 0]
+                               [parent::article or parent::book or parent::part][1]
+             |preceding::setindex[$generate.index != 0][1]
+             |ancestor::set
+             |ancestor::book[1]
+             |ancestor::preface[1]
+             |ancestor::chapter[1]
+             |ancestor::appendix[1]
+             |ancestor::part[1]
+             |ancestor::reference[1]
+             |ancestor::article[1]
+             |ancestor::topic[1]
+             |preceding::sect1[1]
+             |ancestor::sect1[1])[last()]"/>
+
+  <xsl:variable name="next"
+    select="(following::book[1]
+             |following::preface[1]
+             |following::chapter[1]
+             |following::appendix[1]
+             |following::part[1]
+             |following::reference[1]
+             |following::refentry[1]
+             |following::colophon[1]
+             |following::bibliography[parent::article or parent::book or parent::part][1]
+             |following::glossary[parent::article or parent::book or parent::part][1]
+             |following::index[$generate.index != 0]
+                               [parent::article or parent::book][1]
+             |following::article[1]
+             |following::topic[1]
+             |following::setindex[$generate.index != 0][1]
+             |descendant::book[1]
+             |descendant::preface[1]
+             |descendant::chapter[1]
+             |descendant::appendix[1]
+             |descendant::article[1]
+             |descendant::topic[1]
+             |descendant::bibliography[parent::article or parent::book][1]
+             |descendant::glossary[parent::article or parent::book or parent::part][1]
+             |descendant::index[$generate.index != 0]
+                                [parent::article or parent::book][1]
+             |descendant::colophon[1]
+             |descendant::setindex[$generate.index != 0][1]
+             |descendant::part[1]
+             |descendant::reference[1]
+             |descendant::refentry[1]
+             |following::sect1[1]
+             |descendant::sect1[1])[1]"/>
+
+  <xsl:call-template name="process-chunk">
+    <xsl:with-param name="prev" select="$prev"/>
+    <xsl:with-param name="next" select="$next"/>
+    <xsl:with-param name="content" select="$content"/>
+  </xsl:call-template>
+</xsl:template>
+
+<xsl:template name="xxhtml.head">
+  <xsl:param name="prev" select="/foo"/>
+  <xsl:param name="next" select="/foo"/>
+
+  <!-- Optimization for pgsql-docs: Cut out a bunch of things we don't need
+       here, including an expensive //legalnotice search. -->
+
+  <head>
+    <xsl:call-template name="system.head.content"/>
+    <xsl:call-template name="head.content"/>
+
+    <xsl:if test="$prev">
+      <link rel="prev">
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$prev"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:attribute name="title">
+          <xsl:apply-templates select="$prev" mode="object.title.markup.textonly"/>
+        </xsl:attribute>
+      </link>
+    </xsl:if>
+
+    <xsl:if test="$next">
+      <link rel="next">
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$next"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:attribute name="title">
+          <xsl:apply-templates select="$next" mode="object.title.markup.textonly"/>
+        </xsl:attribute>
+      </link>
+    </xsl:if>
+
+    <xsl:call-template name="user.head.content"/>
+  </head>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet-xhtml-dsssl-like-imports.xsl b/doc/src/sgml/stylesheet-xhtml-dsssl-like-imports.xsl
new file mode 100644
index 0000000..9c63aeb
--- /dev/null
+++ b/doc/src/sgml/stylesheet-xhtml-dsssl-like-imports.xsl
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="ASCII"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0">
+
+<!-- ==================================================================== -->
+<!-- from component.xsl -->
+<!-- No chapter toc when there is only one sect1
+xplang.html:
+ Chapter 39. Procedural Languages
+   Table of Contents
+   [9]39.1. Installing Procedural Languages
+->
+ Chapter 39. Procedural Languages
+-->
+<xsl:template match="chapter">
+  <xsl:call-template name="id.warning"/>
+
+  <xsl:element name="{$div.element}" namespace="http://www.w3.org/1999/xhtml">
+    <xsl:call-template name="common.html.attributes">
+      <xsl:with-param name="inherit" select="1"/>
+    </xsl:call-template>
+    <xsl:call-template name="id.attribute">
+      <xsl:with-param name="conditional" select="0"/>
+    </xsl:call-template>
+
+    <xsl:call-template name="component.separator"/>
+    <xsl:call-template name="chapter.titlepage"/>
+
+    <xsl:variable name="toc.params">
+      <xsl:call-template name="find.path.params">
+        <xsl:with-param name="table" select="normalize-space($generate.toc)"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:if test="contains($toc.params, 'toc') and count(sect1) &gt; 1">
+      <xsl:call-template name="component.toc">
+        <xsl:with-param name="toc.title.p" select="contains($toc.params, 'title')"/>
+      </xsl:call-template>
+      <xsl:call-template name="component.toc.separator"/>
+    </xsl:if>
+    <xsl:apply-templates/>
+    <xsl:call-template name="process.footnotes"/>
+  </xsl:element>
+</xsl:template>
+
+<!-- from sections.xsl -->
+<!--
+spi-memory.html:
+ 44.3. Memory Management
+->
+ 44.3. Memory Management
+   Table of Contents
+   SPI_palloc &mdash; allocate memory in the upper executor context
+   SPI_repalloc &mdash; reallocate memory in the upper executor context
+-->
+<xsl:template match="sect1">
+  <xsl:call-template name="id.warning"/>
+
+  <xsl:element name="{$div.element}" namespace="http://www.w3.org/1999/xhtml">
+    <xsl:call-template name="common.html.attributes">
+      <xsl:with-param name="inherit" select="1"/>
+    </xsl:call-template>
+    <xsl:call-template name="id.attribute">
+      <xsl:with-param name="conditional" select="0"/>
+    </xsl:call-template>
+
+    <xsl:choose>
+      <xsl:when test="@renderas = 'sect2'">
+        <xsl:call-template name="sect2.titlepage"/>
+      </xsl:when>
+      <xsl:when test="@renderas = 'sect3'">
+        <xsl:call-template name="sect3.titlepage"/>
+      </xsl:when>
+      <xsl:when test="@renderas = 'sect4'">
+        <xsl:call-template name="sect4.titlepage"/>
+      </xsl:when>
+      <xsl:when test="@renderas = 'sect5'">
+        <xsl:call-template name="sect5.titlepage"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="sect1.titlepage"/>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:variable name="toc.params">
+      <xsl:call-template name="find.path.params">
+        <xsl:with-param name="table" select="normalize-space($generate.toc)"/>
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:if test="contains($toc.params, 'toc')                   and ($generate.section.toc.level &gt;= 1 or count(refentry) &gt; 0)">
+      <xsl:call-template name="section.toc">
+        <xsl:with-param name="toc.title.p" select="contains($toc.params, 'title')"/>
+      </xsl:call-template>
+      <xsl:call-template name="section.toc.separator"/>
+    </xsl:if>
+    <xsl:apply-templates/>
+    <xsl:call-template name="process.chunk.footnotes"/>
+  </xsl:element>
+</xsl:template>
+
+<!-- from xhtml/component.xsl -->
+<!--
+sourcerepo.html:
+
+Appendix I. The Source Code Repository
+   Table of Contents
+   [9]I.1. Getting The Source via Git
+->
+Appendix I. The Source Code Repository
+-->
+<xsl:template match="appendix">
+  <xsl:variable name="ischunk">
+    <xsl:call-template name="chunk"/>
+  </xsl:variable>
+
+  <xsl:call-template name="id.warning"/>
+
+  <xsl:element name="{$div.element}" namespace="http://www.w3.org/1999/xhtml">
+    <xsl:call-template name="common.html.attributes">
+      <xsl:with-param name="inherit" select="1"/>
+    </xsl:call-template>
+    <xsl:call-template name="id.attribute">
+      <xsl:with-param name="conditional" select="0"/>
+    </xsl:call-template>
+
+    <xsl:choose>
+      <xsl:when test="parent::article and $ischunk = 0">
+        <xsl:call-template name="section.heading">
+          <xsl:with-param name="level" select="1"/>
+          <xsl:with-param name="title">
+            <xsl:apply-templates select="." mode="object.title.markup"/>
+          </xsl:with-param>
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="component.separator"/>
+        <xsl:call-template name="appendix.titlepage"/>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:variable name="toc.params">
+      <xsl:call-template name="find.path.params">
+        <xsl:with-param name="table" select="normalize-space($generate.toc)"/>
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:if test="contains($toc.params, 'toc') and count(sect1) &gt; 1">
+      <xsl:call-template name="component.toc">
+        <xsl:with-param name="toc.title.p" select="contains($toc.params, 'title')"/>
+      </xsl:call-template>
+      <xsl:call-template name="component.toc.separator"/>
+    </xsl:if>
+
+    <xsl:apply-templates/>
+
+    <xsl:if test="not(parent::article) or $ischunk != 0">
+      <xsl:call-template name="process.footnotes"/>
+    </xsl:if>
+  </xsl:element>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet-xhtml-dsssl-like.xsl b/doc/src/sgml/stylesheet-xhtml-dsssl-like.xsl
new file mode 100644
index 0000000..dbfcc2e
--- /dev/null
+++ b/doc/src/sgml/stylesheet-xhtml-dsssl-like.xsl
@@ -0,0 +1,1043 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"
+                version="1.0"
+                xmlns="http://www.w3.org/1999/xhtml"
+                exclude-result-prefixes="#default">
+<xsl:import href="stylesheet-xhtml-dsssl-like-imports.xsl" />
+
+<!-- from xhtml/chunk-common.xsl -->
+<!-- align header with dsssl -->
+<xsl:template name="header.navigation">
+  <xsl:param name="prev" select="/foo"/>
+  <xsl:param name="next" select="/foo"/>
+  <xsl:param name="nav.context"/>
+
+  <xsl:variable name="home" select="/*[1]"/>
+  <xsl:variable name="up" select="parent::*"/>
+
+  <xsl:variable name="row1" select="$navig.showtitles != 0"/>
+  <xsl:variable name="row2" select="count($prev) &gt; 0                                     or (count($up) &gt; 0                                          and generate-id($up) != generate-id($home)                                         and $navig.showtitles != 0)                                     or count($next) &gt; 0"/>
+
+  <xsl:if test="$suppress.navigation = '0' and $suppress.header.navigation = '0' and not(self::book)">
+    <div class="navheader">
+      <xsl:if test="$row1 or $row2">
+        <table width="100%" summary="Navigation header">
+          <xsl:if test="$row1">
+            <tr>
+              <th colspan="4" align="center">
+      <a>
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$home"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:apply-templates select="$home" mode="object.title.markup.textonly"/>
+      </a>
+              </th>
+            </tr>
+          </xsl:if>
+
+          <xsl:if test="$row2">
+            <tr>
+              <td width="10%" align="{$direction.align.start}">
+                <xsl:if test="count($prev)&gt;0">
+                  <a accesskey="p">
+                    <xsl:attribute name="href">
+                      <xsl:call-template name="href.target">
+                        <xsl:with-param name="object" select="$prev"/>
+                      </xsl:call-template>
+                    </xsl:attribute>
+                    <xsl:call-template name="navig.content">
+                      <xsl:with-param name="direction" select="'prev'"/>
+                    </xsl:call-template>
+                  </a>
+                </xsl:if>
+                <xsl:text>&#160;</xsl:text>
+              </td>
+              <td width="10%" align="center">
+                <xsl:choose>
+                  <xsl:when test="count($up)&gt;0                                  and generate-id($up) != generate-id($home)">
+                    <a accesskey="u">
+                      <xsl:attribute name="href">
+                        <xsl:call-template name="href.target">
+                          <xsl:with-param name="object" select="$up"/>
+                        </xsl:call-template>
+                      </xsl:attribute>
+                      <xsl:call-template name="navig.content">
+                        <xsl:with-param name="direction" select="'up'"/>
+                      </xsl:call-template>
+                    </a>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <a accesskey="h">
+                      <xsl:attribute name="href">
+                        <xsl:call-template name="href.target">
+                          <xsl:with-param name="object" select="$home"/>
+                        </xsl:call-template>
+                      </xsl:attribute>
+                      <xsl:call-template name="navig.content">
+                        <xsl:with-param name="direction" select="'home'"/>
+                      </xsl:call-template>
+                    </a>
+<!--                    &#160; -->
+               </xsl:otherwise>
+                </xsl:choose>
+              </td>
+              <th width="60%" align="center">
+                <xsl:choose>
+                  <xsl:when test="count($up) &gt; 0  and local-name($up) != 'part' and local-name($up) != 'sect1' and local-name($up) != 'reference'                                    and generate-id($up) != generate-id($home)                                   and $navig.showtitles != 0">
+                    <xsl:apply-templates select="$up" mode="object.title.markup"/>
+                  </xsl:when>
+                  <xsl:otherwise>&#160;</xsl:otherwise>
+                </xsl:choose>
+              </th>
+              <td width="20%" align="{$direction.align.end}">
+                <xsl:text>&#160;</xsl:text>
+                <xsl:if test="count($next)&gt;0">
+                  <a accesskey="n">
+                    <xsl:attribute name="href">
+                      <xsl:call-template name="href.target">
+                        <xsl:with-param name="object" select="$next"/>
+                      </xsl:call-template>
+                    </xsl:attribute>
+                    <xsl:call-template name="navig.content">
+                      <xsl:with-param name="direction" select="'next'"/>
+                    </xsl:call-template>
+                  </a>
+                </xsl:if>
+              </td>
+            </tr>
+          </xsl:if>
+        </table>
+      </xsl:if>
+      <xsl:if test="$header.rule != 0">
+        <hr/>
+      </xsl:if>
+    </div>
+  </xsl:if>
+</xsl:template>
+
+<!-- from xhtml/chunk-common.xsl -->
+<!-- align footer with dsssl -->
+<xsl:template name="footer.navigation">
+  <xsl:param name="prev" select="/foo"/>
+  <xsl:param name="next" select="/foo"/>
+  <xsl:param name="nav.context"/>
+
+  <xsl:variable name="home" select="/*[1]"/>
+  <xsl:variable name="up" select="parent::*"/>
+
+  <xsl:variable name="row1" select="count($prev) &gt; 0                                     or count($up) &gt; 0                                     or count($next) &gt; 0"/>
+
+  <xsl:variable name="row2" select="($prev and $navig.showtitles != 0)                                     or (generate-id($home) != generate-id(.)                                         or $nav.context = 'toc')                                     or ($chunk.tocs.and.lots != 0                                         and $nav.context != 'toc')                                     or ($next and $navig.showtitles != 0)"/>
+
+  <xsl:if test="$suppress.navigation = '0' and $suppress.footer.navigation = '0'">
+    <div class="navfooter">
+      <xsl:if test="$footer.rule != 0">
+        <hr/>
+      </xsl:if>
+
+      <xsl:if test="$row1 or $row2">
+        <table width="100%" summary="Navigation footer">
+          <xsl:if test="$row1">
+            <tr>
+              <td width="40%" align="{$direction.align.start}">
+                <xsl:if test="count($prev)&gt;0">
+                  <a accesskey="p">
+                    <xsl:attribute name="href">
+                      <xsl:call-template name="href.target">
+                        <xsl:with-param name="object" select="$prev"/>
+                      </xsl:call-template>
+                    </xsl:attribute>
+                    <xsl:call-template name="navig.content">
+                      <xsl:with-param name="direction" select="'prev'"/>
+                    </xsl:call-template>
+                  </a>
+                </xsl:if>
+                <xsl:text>&#160;</xsl:text>
+              </td>
+              <td width="20%" align="center">
+                <xsl:choose>
+                  <xsl:when test="$home != . or $nav.context = 'toc'">
+                    <a accesskey="h">
+                      <xsl:attribute name="href">
+                        <xsl:call-template name="href.target">
+                          <xsl:with-param name="object" select="$home"/>
+                        </xsl:call-template>
+                      </xsl:attribute>
+                      <xsl:call-template name="navig.content">
+                        <xsl:with-param name="direction" select="'home'"/>
+                      </xsl:call-template>
+                    </a>
+                    <xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'">
+                      <xsl:text>&#160;|&#160;</xsl:text>
+                    </xsl:if>
+                  </xsl:when>
+                  <xsl:otherwise>&#160;</xsl:otherwise>
+                </xsl:choose>
+
+                <xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'">
+                  <a accesskey="t">
+                    <xsl:attribute name="href">
+                      <xsl:value-of select="$chunked.filename.prefix"/>
+                      <xsl:apply-templates select="/*[1]" mode="recursive-chunk-filename">
+                        <xsl:with-param name="recursive" select="true()"/>
+                      </xsl:apply-templates>
+                      <xsl:text>-toc</xsl:text>
+                      <xsl:value-of select="$html.ext"/>
+                    </xsl:attribute>
+                    <xsl:call-template name="gentext">
+                      <xsl:with-param name="key" select="'nav-toc'"/>
+                    </xsl:call-template>
+                  </a>
+                </xsl:if>
+              </td>
+              <td width="40%" align="{$direction.align.end}">
+                <xsl:text>&#160;</xsl:text>
+                <xsl:if test="count($next)&gt;0">
+                  <a accesskey="n">
+                    <xsl:attribute name="href">
+                      <xsl:call-template name="href.target">
+                        <xsl:with-param name="object" select="$next"/>
+                      </xsl:call-template>
+                    </xsl:attribute>
+                    <xsl:call-template name="navig.content">
+                      <xsl:with-param name="direction" select="'next'"/>
+                    </xsl:call-template>
+                  </a>
+                </xsl:if>
+              </td>
+            </tr>
+          </xsl:if>
+
+          <xsl:if test="$row2">
+            <tr>
+              <td width="40%" align="{$direction.align.start}" valign="top">
+                <xsl:if test="$navig.showtitles != 0">
+                  <xsl:apply-templates select="$prev" mode="object.title.markup.textonly"/>
+                </xsl:if>
+                <xsl:text>&#160;</xsl:text>
+              </td>
+              <td width="20%" align="center">
+                <xsl:choose>
+                  <xsl:when test="count($up)&gt;0                                   and generate-id($up) != generate-id($home)">
+                    <a accesskey="u">
+                      <xsl:attribute name="href">
+                        <xsl:call-template name="href.target">
+                          <xsl:with-param name="object" select="$up"/>
+                        </xsl:call-template>
+                      </xsl:attribute>
+                      <xsl:call-template name="navig.content">
+                        <xsl:with-param name="direction" select="'up'"/>
+                      </xsl:call-template>
+                    </a>
+                  </xsl:when>
+                  <xsl:otherwise>&#160;</xsl:otherwise>
+                </xsl:choose>
+              </td>
+              <td width="40%" align="{$direction.align.end}" valign="top">
+                <xsl:text>&#160;</xsl:text>
+                <xsl:if test="$navig.showtitles != 0">
+                  <xsl:apply-templates select="$next" mode="object.title.markup.textonly"/>
+                </xsl:if>
+              </td>
+            </tr>
+          </xsl:if>
+        </table>
+      </xsl:if>
+    </div>
+  </xsl:if>
+</xsl:template>
+<!-- ==================================================================== -->
+
+<!-- from xhtml/chunk-common.xsl -->
+<!-- Modify html.head -->
+<xsl:template name="html.head">
+  <xsl:param name="prev" select="/foo"/>
+  <xsl:param name="next" select="/foo"/>
+  <xsl:variable name="this" select="."/>
+  <xsl:variable name="home" select="/*[1]"/>
+  <xsl:variable name="up" select="parent::*"/>
+
+  <head>
+    <xsl:call-template name="system.head.content"/>
+    <xsl:call-template name="head.content"/>
+
+    <!-- home link not valid in HTML5 -->
+    <xsl:if test="$home and $div.element != 'section' and not(self::book)">
+      <link rel="home">
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$home"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:attribute name="title">
+          <xsl:apply-templates select="$home" mode="object.title.markup.textonly"/>
+        </xsl:attribute>
+      </link>
+    </xsl:if>
+
+    <!-- up link not valid in HTML5 -->
+    <xsl:if test="$up and $div.element != 'section' and generate-id($up) != generate-id($home)"> <!-- LAW -->
+      <link rel="up">
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$up"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:attribute name="title">
+          <xsl:apply-templates select="$up" mode="object.title.markup.textonly"/>
+        </xsl:attribute>
+      </link>
+    </xsl:if>
+
+    <xsl:if test="$prev">
+      <link rel="prev">
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$prev"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:attribute name="title">
+          <xsl:apply-templates select="$prev" mode="object.title.markup.textonly"/>
+        </xsl:attribute>
+      </link>
+    </xsl:if>
+
+    <xsl:if test="$next">
+      <link rel="next">
+        <xsl:attribute name="href">
+          <xsl:call-template name="href.target">
+            <xsl:with-param name="object" select="$next"/>
+          </xsl:call-template>
+        </xsl:attribute>
+        <xsl:attribute name="title">
+          <xsl:apply-templates select="$next" mode="object.title.markup.textonly"/>
+        </xsl:attribute>
+      </link>
+    </xsl:if>
+
+    <xsl:if test="$html.extra.head.links != 0">
+      <xsl:for-each select="//part                             |//reference                             |//preface                             |//chapter                             |//article                             |//refentry                             |//appendix[not(parent::article)]|appendix                             |//glossary[not(parent::article)]|glossary                             |//index[not(parent::article)]|index">
+        <link rel="{local-name(.)}">
+          <xsl:attribute name="href">
+            <xsl:call-template name="href.target">
+              <xsl:with-param name="context" select="$this"/>
+              <xsl:with-param name="object" select="."/>
+            </xsl:call-template>
+          </xsl:attribute>
+          <xsl:attribute name="title">
+            <xsl:apply-templates select="." mode="object.title.markup.textonly"/>
+          </xsl:attribute>
+        </link>
+      </xsl:for-each>
+
+      <xsl:for-each select="section|sect1|refsection|refsect1">
+        <link>
+          <xsl:attribute name="rel">
+            <xsl:choose>
+              <xsl:when test="local-name($this) = 'section'                               or local-name($this) = 'refsection'">
+                <xsl:value-of select="'subsection'"/>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:value-of select="'section'"/>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:attribute>
+          <xsl:attribute name="href">
+            <xsl:call-template name="href.target">
+              <xsl:with-param name="context" select="$this"/>
+              <xsl:with-param name="object" select="."/>
+            </xsl:call-template>
+          </xsl:attribute>
+          <xsl:attribute name="title">
+            <xsl:apply-templates select="." mode="object.title.markup.textonly"/>
+          </xsl:attribute>
+        </link>
+      </xsl:for-each>
+
+      <xsl:for-each select="sect2|sect3|sect4|sect5|refsect2|refsect3">
+        <link rel="subsection">
+          <xsl:attribute name="href">
+            <xsl:call-template name="href.target">
+              <xsl:with-param name="context" select="$this"/>
+              <xsl:with-param name="object" select="."/>
+            </xsl:call-template>
+          </xsl:attribute>
+          <xsl:attribute name="title">
+            <xsl:apply-templates select="." mode="object.title.markup.textonly"/>
+          </xsl:attribute>
+        </link>
+      </xsl:for-each>
+    </xsl:if>
+
+    <!-- * if we have a legalnotice and user wants it output as a -->
+    <!-- * separate page and $html.head.legalnotice.link.types is -->
+    <!-- * non-empty, we generate a link or links for each value in -->
+    <!-- * $html.head.legalnotice.link.types -->
+<!--    <xsl:if test="//legalnotice                   and not($generate.legalnotice.link = 0)                   and not($html.head.legalnotice.link.types = '')">
+      <xsl:call-template name="make.legalnotice.head.links"/>
+    </xsl:if> -->
+
+    <xsl:call-template name="user.head.content"/>
+  </head>
+</xsl:template>
+
+<!-- ==================================================================== -->
+
+<!-- from common/gentext.xsl -->
+<!-- admin.html:
+"14.5. Non-Durable Settings" -> "Non-Durable Settings"
+"Chapter 15. Installation from Source Code" -> "Installation from Source Code"
+ -->
+<xsl:template match="*" mode="object.title.markup.textonly">
+  <xsl:variable name="template">
+    <xsl:call-template name="gentext.template">
+      <xsl:with-param name="context"><xsl:choose>
+        <xsl:when test="local-name()='part' or
+                        local-name()='chapter' or
+                        local-name()='appendix' or
+                        local-name()='sect1' or
+                        local-name()='sect2' or
+                        local-name()='sect3' or
+                        local-name()='sect4' or
+                        local-name()='sect5' or
+                        local-name()='simplesect'">title-unnumbered</xsl:when>
+        <xsl:otherwise>title</xsl:otherwise>
+      </xsl:choose></xsl:with-param>
+      <xsl:with-param name="name">
+        <xsl:call-template name="xpath.location"/>
+      </xsl:with-param>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:variable name="title">
+    <xsl:call-template name="substitute-markup">
+      <xsl:with-param name="allow-anchors" select="0"/>
+      <xsl:with-param name="template" select="$template"/>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:value-of select="normalize-space($title)"/>
+</xsl:template>
+
+<!-- from common/gentext.xsl (based on <xsl:template match="*" mode="object.title.markup">)-->
+<!-- admin.html: "Part III. Server Administration -> III. Server Administration" -->
+<xsl:template match="part" mode="object.title.markup">
+  <xsl:param name="allow-anchors" select="0"/>
+  <xsl:variable name="template">%n. %t
+<!--    <xsl:apply-templates select="." mode="object.title.template"/> -->
+  </xsl:variable>
+
+<!--
+  <xsl:message>
+    <xsl:text>object.title.markup: </xsl:text>
+    <xsl:value-of select="local-name(.)"/>
+    <xsl:text>: </xsl:text>
+    <xsl:value-of select="$template"/>
+  </xsl:message>
+-->
+  <xsl:call-template name="substitute-markup">
+    <xsl:with-param name="allow-anchors" select="$allow-anchors"/>
+    <xsl:with-param name="template" select="$template"/>
+  </xsl:call-template>
+</xsl:template>
+
+<!-- from common/gentext.xsl (based on <xsl:template match="*" mode="object.xref.template">) -->
+<!-- contrib-prog-client.html: "see also PostgreSQL Client Applications" -> "see also Reference II, PostgreSQL Client Applications" -->
+<xsl:template match="reference"
+              mode="object.xref.template">
+  <xsl:variable name="title">
+      <xsl:call-template name="gentext">
+        <xsl:with-param name="key" select="'Reference'"/>
+      </xsl:call-template>
+  </xsl:variable>
+  <xsl:value-of select='concat($title, " %n, %t")' />
+</xsl:template>
+<!-- ==================================================================== -->
+
+<!-- from xhtml/chunk-code.xsl (see stylesheet-xhtml-dsssl-like-imports.xsl) -->
+<xsl:template match="chapter|sect1|appendix">
+  <xsl:choose>
+    <xsl:when test="$onechunk != 0 and parent::*">
+      <xsl:apply-imports/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:call-template name="process-chunk-element"/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+<!-- ==================================================================== -->
+
+<!-- from xhtml/admon.xsl -->
+<!-- app-psql.html:
+          This mode is provided for those who insist on it, but you are
+          not necessarily encouraged to use it. In particular, if you mix
+          SQL and meta-commands on a line the order of execution might not
+          always be clear to the inexperienced user.
+->
+     This mode is provided for those who insist on it, but you are not
+     necessarily encouraged to use it. In particular, if you mix SQL and
+     meta-commands on a line the order of execution might not always be
+     clear to the inexperienced user.
+-->
+<xsl:template name="nongraphical.admonition">
+  <div>
+    <xsl:call-template name="common.html.attributes">
+      <xsl:with-param name="inherit" select="1"/>
+    </xsl:call-template>
+    <xsl:call-template name="id.attribute"/>
+    <xsl:if test="$admon.style != '' and $make.clean.html = 0">
+      <xsl:attribute name="style">
+        <xsl:value-of select="$admon.style"/>
+      </xsl:attribute>
+    </xsl:if>
+
+    <xsl:choose>
+      <xsl:when test="local-name()='warning' or local-name()='caution'">
+        <table>
+        <xsl:call-template name="common.html.attributes">
+            <xsl:with-param name="inherit" select="1"/>
+        </xsl:call-template>
+        <xsl:attribute name="width">90%</xsl:attribute>
+        <xsl:attribute name="border">1</xsl:attribute>
+    <xsl:if test="$admon.textlabel != 0 or title or info/title">
+        <tr><td align="center"><b>
+        <xsl:call-template name="anchor"/>
+        <xsl:apply-templates select="." mode="object.title.markup"/>
+        </b></td></tr>
+    </xsl:if>
+        <tr><td align="left">
+        <xsl:apply-templates/>
+        </td></tr>
+        </table>
+      </xsl:when>
+      <xsl:otherwise>
+        <blockquote>
+        <xsl:call-template name="common.html.attributes">
+            <xsl:with-param name="inherit" select="1"/>
+        </xsl:call-template>
+    <xsl:if test="$admon.textlabel != 0 or title or info/title">
+      <h3 class="title">
+        <xsl:call-template name="anchor"/>
+        <xsl:apply-templates select="." mode="object.title.markup"/>
+      </h3>
+    </xsl:if>
+    <xsl:apply-templates/>
+        </blockquote>
+      </xsl:otherwise>
+    </xsl:choose>
+  </div>
+</xsl:template>
+
+<xsl:param name="admon.style">
+  <xsl:value-of select="concat('margin-', $direction.align.start,            ': 0px; margin-', $direction.align.end, ': 0px;')"/>
+</xsl:param>
+
+<!-- ==================================================================== -->
+<!-- from xhtml/block.xsl -->
+<!--
+auth-pg-hba-conf.htm:
+          Users sometimes wonder why host names are handled in this
+          seemingly complicated way, with two name resolutions including a
+          reverse lookup of the client's IP address. This complicates use
+->
+         Users sometimes wonder why host names are handled in this seemingly
+         complicated way, with two name resolutions including a reverse lookup
+         of the client's IP address. This complicates use of the feature in case
+
+-->
+<xsl:template match="sidebar">
+  <table cellpadding="5" border="1">
+    <xsl:call-template name="common.html.attributes"/>
+  <tr><td>
+  <div>
+    <xsl:call-template name="common.html.attributes"/>
+    <xsl:call-template name="id.attribute"/>
+    <xsl:call-template name="anchor"/>
+    <xsl:call-template name="sidebar.titlepage"/>
+    <xsl:apply-templates/>
+  </div>
+  </td></tr></table>
+</xsl:template>
+
+<!-- ==================================================================== -->
+<!-- from xhtml/refentry.xsl -->
+<!--
+
+app-clusterdb.html:
+     __________________________________________________________________
+->
+   _______________________________________________________________________
+
+                                   clusterdb
+-->
+<xsl:template match="refnamediv">
+  <div>
+    <xsl:call-template name="common.html.attributes">
+      <xsl:with-param name="inherit" select="1"/>
+    </xsl:call-template>
+    <xsl:call-template name="id.attribute"/>
+    <xsl:call-template name="anchor"/>
+    <xsl:choose>
+      <xsl:when test="preceding-sibling::refnamediv">
+        <!-- no title on secondary refnamedivs! -->
+      </xsl:when>
+      <xsl:when test="$refentry.generate.title != 0">
+        <h1 align="center">
+          <xsl:choose>
+            <xsl:when test="../refmeta/refentrytitle">
+              <xsl:apply-templates select="../refmeta/refentrytitle"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:apply-templates select="refname[1]"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </h1>
+      </xsl:when>
+    </xsl:choose>
+        <h2>
+          <xsl:call-template name="gentext">
+            <xsl:with-param name="key" select="'RefName'"/>
+          </xsl:call-template>
+        </h2>
+
+    <p>
+      <xsl:apply-templates/>
+    </p>
+  </div>
+</xsl:template>
+
+<!-- ==================================================================== -->
+
+<!-- from common/common.xsl -->
+<!-- app-clusterdb.html:
+   clusterdb [connection-option...] [ -_-verbose | -v ] -_-all | -a
+->
+   clusterdb [connection-option...] [-_-verbose | -v] -_-all | -a
+-->
+<xsl:param name="arg.choice.plain.open.str"><xsl:text></xsl:text></xsl:param>
+<xsl:param name="arg.choice.plain.close.str"><xsl:text></xsl:text></xsl:param>
+
+<!-- ==================================================================== -->
+
+<!-- from xhml/autotoc.xls -->
+<!-- Add subtoc for sect1/refentry and sect1/simplesect
+ecpg.html:
+   33.14. Embedded SQL Commands
+   33.15. Informix Compatibility Mode
+->
+   33.14. Embedded SQL Commands
+        ALLOCATE DESCRIPTOR — allocate an SQL descriptor area
+        CONNECT — establish a database connection
+...
+   33.15. Informix Compatibility Mode
+
+-->
+<xsl:template match="sect1" mode="toc">
+  <xsl:param name="toc-context" select="."/>
+  <xsl:call-template name="subtoc">
+    <xsl:with-param name="toc-context" select="$toc-context"/>
+    <xsl:with-param name="nodes" select="sect2|refentry|simplesect                                          |bridgehead[$bridgehead.in.toc != 0]"/>
+  </xsl:call-template>
+</xsl:template>
+
+<!-- from xhtml/autotoc.xsl -->
+<!-- Change subtoc output condition
+contrib.html:
+    F.1. adminpack
+        F.1.1. Functions Implemented
+    F.2. auth_delay
+        F.2.1. Configuration Parameters
+        F.2.2. Author
+    F.3. auto_explain
+->
+    F.1. adminpack
+    F.2. auth_delay
+    F.3. auto_explain
+
+-->
+<xsl:template name="subtoc">
+  <xsl:param name="toc-context" select="."/>
+  <xsl:param name="nodes" select="NOT-AN-ELEMENT"/>
+
+  <xsl:variable name="nodes.plus" select="$nodes | qandaset"/>
+
+  <xsl:variable name="subtoc">
+    <xsl:element name="{$toc.list.type}" namespace="http://www.w3.org/1999/xhtml">
+      <xsl:choose>
+        <xsl:when test="$qanda.in.toc != 0">
+          <xsl:apply-templates mode="toc" select="$nodes.plus">
+            <xsl:with-param name="toc-context" select="$toc-context"/>
+          </xsl:apply-templates>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:apply-templates mode="toc" select="$nodes">
+            <xsl:with-param name="toc-context" select="$toc-context"/>
+          </xsl:apply-templates>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:element>
+  </xsl:variable>
+
+  <xsl:variable name="depth">
+    <xsl:choose>
+      <xsl:when test="local-name(.) = 'section'">
+        <xsl:value-of select="count(ancestor::section) + 1"/>
+      </xsl:when>
+      <xsl:when test="local-name(.) = 'sect1'">1</xsl:when>
+      <xsl:when test="local-name(.) = 'sect2'">2</xsl:when>
+      <xsl:when test="local-name(.) = 'sect3'">3</xsl:when>
+      <xsl:when test="local-name(.) = 'sect4'">4</xsl:when>
+      <xsl:when test="local-name(.) = 'sect5'">5</xsl:when>
+      <xsl:when test="local-name(.) = 'refsect1'">1</xsl:when>
+      <xsl:when test="local-name(.) = 'refsect2'">2</xsl:when>
+      <xsl:when test="local-name(.) = 'refsect3'">3</xsl:when>
+      <xsl:when test="local-name(.) = 'topic'">1</xsl:when>
+      <xsl:when test="local-name(.) = 'simplesect'">
+        <!-- sigh... -->
+        <xsl:choose>
+          <xsl:when test="local-name(..) = 'section'">
+            <xsl:value-of select="count(ancestor::section)"/>
+          </xsl:when>
+          <xsl:when test="local-name(..) = 'sect1'">2</xsl:when>
+          <xsl:when test="local-name(..) = 'sect2'">3</xsl:when>
+          <xsl:when test="local-name(..) = 'sect3'">4</xsl:when>
+          <xsl:when test="local-name(..) = 'sect4'">5</xsl:when>
+          <xsl:when test="local-name(..) = 'sect5'">6</xsl:when>
+          <xsl:when test="local-name(..) = 'topic'">2</xsl:when>
+          <xsl:when test="local-name(..) = 'refsect1'">2</xsl:when>
+          <xsl:when test="local-name(..) = 'refsect2'">3</xsl:when>
+          <xsl:when test="local-name(..) = 'refsect3'">4</xsl:when>
+          <xsl:otherwise>1</xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="depth.from.context" select="count(ancestor::*)-count($toc-context/ancestor::*)"/>
+
+  <xsl:variable name="subtoc.list">
+    <xsl:choose>
+      <xsl:when test="$toc.dd.type = ''">
+        <xsl:copy-of select="$subtoc"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:element name="{$toc.dd.type}" namespace="http://www.w3.org/1999/xhtml">
+          <xsl:copy-of select="$subtoc"/>
+        </xsl:element>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+  <xsl:variable name="output.subtoc"><xsl:value-of select="
+    ( (self::set or self::book or self::part) or
+       ($toc.section.depth &gt; $depth and local-name($toc-context)!='appendix' and local-name($toc-context)!='preface') ) and
+    ( ($qanda.in.toc = 0 and (count($nodes)&gt;1 or (count($nodes)&gt;0 and ($toc.section.depth - 1 &gt; $depth)) )) or
+      ($qanda.in.toc != 0 and (count($nodes.plus)&gt;1 or (count($nodes)&gt;0 and $toc.section.depth - 1 &gt; $depth) ))) and 
+      $toc.max.depth &gt; $depth.from.context
+      "/></xsl:variable>
+  <xsl:element name="{$toc.listitem.type}" namespace="http://www.w3.org/1999/xhtml">
+    <xsl:call-template name="toc.line">
+      <xsl:with-param name="toc-context" select="$toc-context"/>
+    </xsl:call-template>
+    <xsl:if test="$toc.listitem.type = 'li' and $output.subtoc = 'true'">
+      <xsl:copy-of select="$subtoc.list"/>
+    </xsl:if>
+  </xsl:element>
+  <xsl:if test="$toc.listitem.type != 'li' and $output.subtoc = 'true'">
+    <xsl:copy-of select="$subtoc.list"/>
+  </xsl:if>
+</xsl:template>
+
+<!-- from common/labels.xsl -->
+<!--
+preface.html:
+1. What is PostgreSQL?
+2. A Brief History of PostgreSQL
+3. Conventions
+->
+What is PostgreSQL?
+A Brief History of PostgreSQL
+Conventions
+-->
+<xsl:template name="label.this.section">
+  <xsl:param name="section" select="."/>
+
+  <xsl:variable name="level">
+    <xsl:call-template name="section.level"/>
+  </xsl:variable>
+
+  <xsl:choose>
+    <!-- bridgeheads are not numbered -->
+    <xsl:when test="$section/self::bridgehead">0</xsl:when>
+    <xsl:when test="ancestor::preface">0</xsl:when>
+    <xsl:when test="$level &lt;= $section.autolabel.max.depth">
+      <xsl:value-of select="$section.autolabel"/>
+    </xsl:when>
+    <xsl:otherwise>0</xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+
+<!-- from common/gentext.xsl -->
+<!-- error-style-guide.html:
+What Goes Where
+->
+51.3.1. What Goes Where
+-->
+<xsl:template match="simplesect"
+              mode="object.title.template">
+<xsl:text>%n. %t</xsl:text>
+</xsl:template>
+
+<!-- based on xhtml/component.xsl: <xsl:template match="topic/title|topic/info/title" mode="titlepage.mode" priority="2"> -->
+<!-- sql-commands.html:
+SQL Commands
+->
+I. SQL Commands
+-->
+<xsl:template match="reference/title" mode="titlepage.mode" priority="2">
+  <xsl:call-template name="component.title">
+    <xsl:with-param name="node" select="ancestor::reference[1]"/>
+  </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="reference"
+              mode="object.title.template">
+<xsl:text>%n. %t</xsl:text>
+</xsl:template>
+
+<!-- from xhtml/footnote.xsl -->
+<!--
+<sup>[1]</sup> -> <span>[1]</span>
+
+datatype-json.html:
+each value in the data. ^[16]
+->
+each value in the data. [16]
+-->
+<xsl:template match="footnote">
+  <xsl:variable name="name">
+    <xsl:call-template name="object.id">
+      <xsl:with-param name="conditional" select="0"/>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:variable name="href">
+    <xsl:text>#ftn.</xsl:text>
+    <xsl:value-of select="$name"/>
+  </xsl:variable>
+
+  <a href="{$href}">
+    <xsl:apply-templates select="." mode="class.attribute"/>
+    <xsl:if test="$generate.id.attributes = 0">
+      <xsl:attribute name="id">
+        <xsl:value-of select="$name"/>
+      </xsl:attribute>
+    </xsl:if>
+
+    <span> <!-- instead of <sup> -->
+      <xsl:apply-templates select="." mode="class.attribute"/>
+      <xsl:call-template name="id.attribute">
+        <xsl:with-param name="conditional" select="0"/>
+      </xsl:call-template>
+      <xsl:text>[</xsl:text>
+      <xsl:apply-templates select="." mode="footnote.number"/>
+      <xsl:text>]</xsl:text>
+    </span>
+  </a>
+</xsl:template>
+
+<!-- from xhtml/footnote.xsl -->
+<!--
+<sup>[1]</sup> -> <span>[1]</span>
+
+datatype-json.html:
++   ^[1] For this purpose, the term "value" includes array elements,
++   though JSON terminology sometimes considers array elements distinct
+->
++   [1] For this purpose, the term "value" includes array elements,
++   though JSON terminology sometimes considers array elements distinct
+-->
+<xsl:template match="footnote/para[1]|footnote/simpara[1]" priority="2">
+  <!-- this only works if the first thing in a footnote is a para, -->
+  <!-- which is ok, because it usually is. -->
+  <xsl:variable name="href">
+    <xsl:text>#</xsl:text>
+    <xsl:call-template name="object.id">
+      <xsl:with-param name="object" select="ancestor::footnote"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:call-template name="paragraph">
+    <xsl:with-param name="class">
+      <xsl:if test="@role and $para.propagates.style != 0">
+        <xsl:value-of select="@role"/>
+      </xsl:if>
+    </xsl:with-param>
+    <xsl:with-param name="content">
+      <a href="{$href}">
+        <xsl:apply-templates select="." mode="class.attribute"/>
+        <span>
+          <xsl:apply-templates select="." mode="class.attribute"/>
+          <xsl:text>[</xsl:text>
+          <xsl:apply-templates select="ancestor::footnote" mode="footnote.number"/>
+          <xsl:text>] </xsl:text>
+        </span>
+      </a>
+      <p>
+      <xsl:attribute name="style">margin-left:5%</xsl:attribute>
+      <xsl:apply-templates/>
+      </p>
+    </xsl:with-param>
+  </xsl:call-template>
+
+</xsl:template>
+
+<!-- Custom function for chunk numbering -->
+<xsl:template name="footnote.in.chunk.number">
+  <xsl:param name="node" select="."/>
+  <xsl:param name="footnote" select="."/>
+
+  <xsl:variable name="is.chunk">
+    <xsl:call-template name="chunk">
+      <xsl:with-param name="node" select="$node"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:choose>
+    <xsl:when test="$is.chunk = 1">
+      <xsl:value-of select="count($node//footnote[not(@label)][count(./preceding::node()) &lt;= count($node//footnote[not(@label)][.=$footnote]/preceding::node())])" />
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:if test="$node/parent::*">
+        <xsl:call-template name="footnote.in.chunk.number">
+          <xsl:with-param name="node" select="$node/parent::*"/>
+          <xsl:with-param name="footnote" select="$footnote"/>
+        </xsl:call-template>
+      </xsl:if>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!-- from xhtml/footnote.xsl
+Independent footnote numbering inside chunks
+error-message-reporting.html:
+ [11] %m does not require any corresponding entry in the parameter list for errmsg.
+->
+ [1] %m does not require any corresponding entry in the parameter list for errmsg.
+-->
+<xsl:template match="footnote" mode="footnote.number">
+  <xsl:choose>
+    <xsl:when test="string-length(@label) != 0">
+      <xsl:value-of select="@label"/>
+    </xsl:when>
+    <xsl:when test="ancestor::table or ancestor::informaltable">
+      <xsl:variable name="tfnum">
+        <xsl:number level="any" from="table|informaltable" format="1"/>
+      </xsl:variable>
+
+      <xsl:choose>
+        <xsl:when test="string-length($table.footnote.number.symbols) &gt;= $tfnum">
+          <xsl:value-of select="substring($table.footnote.number.symbols, $tfnum, 1)"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:number level="any" from="table | informaltable" format="{$table.footnote.number.format}"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:variable name="fnum"> <!--"count($pfoot) - count($ptfoot) + 1"/> -->
+        <xsl:choose>
+          <xsl:when test="$onechunk != 0">
+            <xsl:variable name="pfoot" select="preceding::footnote[not(@label)]"/>
+            <xsl:variable name="ptfoot" select="preceding::table//footnote |                                           preceding::informaltable//footnote"/>
+            <xsl:value-of select="count($pfoot) - count($ptfoot) + 1"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:call-template name="footnote.in.chunk.number">
+            </xsl:call-template>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="string-length($footnote.number.symbols) &gt;= $fnum">
+          <xsl:value-of select="substring($footnote.number.symbols, $fnum, 1)"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:number value="$fnum" format="{$footnote.number.format}"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!-- from xhtml/xref.xsl -->
+<!--
+tutorial-sql-intro.html:
+   written on SQL, including [melt93] and [date97].
+->
+   written on SQL, including Understanding the New SQL and A Guide
+   to the SQL Standard.
+-->
+<xsl:template match="biblioentry|bibliomixed" mode="xref-to">
+  <xsl:param name="referrer"/>
+  <xsl:param name="xrefstyle"/>
+  <xsl:param name="verbose" select="1"/>
+ <!-- handles both biblioentry and bibliomixed -->
+
+  <xsl:choose>
+    <xsl:when test="string(.) = ''">
+      <xsl:variable name="bib" select="document($bibliography.collection,.)"/>
+      <xsl:variable name="id" select="(@id|@xml:id)[1]"/>
+      <xsl:variable name="entry" select="$bib/bibliography/                                     *[@id=$id or @xml:id=$id][1]"/>
+      <xsl:choose>
+        <xsl:when test="$entry">
+          <xsl:choose>
+            <xsl:when test="$bibliography.numbered != 0">
+              <xsl:number from="bibliography" count="biblioentry|bibliomixed" level="any" format="1"/>
+            </xsl:when>
+            <xsl:when test="local-name($entry/*[1]) = 'abbrev'">
+              <xsl:apply-templates select="$entry/*[1]" mode="no.anchor.mode"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="(@id|@xml:id)[1]"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:message>
+            <xsl:text>No bibliography entry: </xsl:text>
+            <xsl:value-of select="$id"/>
+            <xsl:text> found in </xsl:text>
+            <xsl:value-of select="$bibliography.collection"/>
+          </xsl:message>
+          <xsl:value-of select="(@id|@xml:id)[1]"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:choose>
+        <xsl:when test="$bibliography.numbered != 0">
+          <xsl:number from="bibliography" count="biblioentry|bibliomixed" level="any" format="1"/>
+        </xsl:when>
+        <xsl:when test="local-name(*[1]) = 'abbrev'">
+          <xsl:apply-templates select="*[1]" mode="no.anchor.mode"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="normalize-space((title|(biblioset[1]/title))[1])"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!-- from xhtml/xref.xsl -->
+<xsl:template match="biblioentry|bibliomixed" mode="xref-to-prefix">
+</xsl:template>
+
+<!-- from xhtml/xref.xsl -->
+<xsl:template match="biblioentry|bibliomixed" mode="xref-to-suffix">
+</xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet.xsl b/doc/src/sgml/stylesheet.xsl
index 7967b36..70cdecf 100644
--- a/doc/src/sgml/stylesheet.xsl
+++ b/doc/src/sgml/stylesheet.xsl
@@ -7,6 +7,9 @@
 <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
 <xsl:include href="stylesheet-common.xsl" />
 
+<xsl:include href="stylesheet-speedup-common.xsl" />
+<xsl:include href="stylesheet-speedup-xhtml.xsl" />
+<xsl:include href="stylesheet-xhtml-dsssl-like.xsl" />
 
 <!-- Parameters -->
 <xsl:param name="base.dir" select="'html/'"></xsl:param>
@@ -19,6 +22,9 @@
 <xsl:param name="chunk.quietly" select="1"></xsl:param>
 <xsl:param name="toc.max.depth">2</xsl:param>
 
+<xsl:param name="refentry.generate.name" select="1"/>
+<xsl:param name="refentry.generate.title" select="1"/>
+<xsl:param name="xref.with.number.and.title" select="0"></xsl:param>
 <xsl:param name="website.stylesheet" select="0"/>
 
 <xsl:param name="html.stylesheet">
@@ -49,7 +55,7 @@ preface   toc,title
 qandadiv  toc
 qandaset  toc
 reference toc,title
-sect1     toc
+sect1     toc,title
 sect2     toc
 sect3     toc
 sect4     toc

---

From: Jürgen Purtz <[email-masked]>
Date: Sat, 2 Jul 2016 12:14:26 +0200

> - Then consider upgrading to DocBook 5. [milestone 3]

During the step from DocBook 4 to DocBook 5 [M3] we will face the 
problem that there are incompatibilities in the DocBook structure. Our 
source is affected by:

 1. It's no longer possible to use <option> and <optional> in a
    recursive fashion.
 2. The content model of <literal>, <function>, <command> and similar
    elements has changed.

In my opinion the first issue is not acceptable and the second one may 
need some DocBook redesign as well as manual changes in our source code. 
The DocBook TC has accepted this concerns and works on a solution. But 
as they are in the last phase of bringing 5.1 to an official OASIS 
standard, we probably have to wait (a long time) until 5.2. You can 
follow the discussion here: 
https://lists.oasis-open.org/archives/docbook/201606/msg00007.html and 
in a direct mail from Bob Stayton:

-----
Hi,
I'm investigating this issue.  I'm trying to track down the history and 
reasoning for this change, but have not yet completed that research.  It 
looks like a mistake to me to limit the content model so much when we 
were consciously trying to maintain backwards compatibility unless there 
were good reasons not to.

Bob Stayton
Sagehill Enterprises
[email-masked]
-----

Jürgen Purtz

Btw: Since 16 June 2016 Norman Welsh is no longer chairman of the TC. 
Now Bob holds this position, Norman changed to a 'normal' member of the TC.

---

From: Peter Eisentraut <[email-masked]>
Date: Thu, 18 Aug 2016 13:56:52 -0400

> this off into a separate commit.

I have committed the first part of this, as discussed.

---

From: Alexander Law <[email-masked]>
Date: Fri, 19 Aug 2016 16:14:04 +0300

Great!

The next items in our plan were:

- Wait a while to make sure everyone is happy with the performance. Keep 
tweaking if necessary.
- Port all DSSSL customizations to XSLT.  Manually evaluate output for 
quality.

Should we now compare DSSSL outputs with XSLT?
I had some success with it before. See my letter:
https://www.postgresql.org/message-id/57712848.7060306%40gmail.com
Those xslt's (see xhtml-like-dsssl.patch) can help us to see all the 
differences and to decide which customizations to keep.

Best regards,
Alexander

---

From: Peter Eisentraut <[email-masked]>
Date: Mon, 22 Aug 2016 14:06:52 -0400

> The next items in our plan were:

An immediate problem is that the patched stuff no longer works with
older stylesheets (1.76.1?).  I'm glad to leave older stuff behind for a
400% speedup, but we need to analyze the exact effect and possibly
document it or work around it.

> differences and to decide which customizations to keep.

It looks like the idea there is to whack the XSLT stylesheets until the
output looks exactly like the DSSSL output?  I'm not sure that's
terribly useful.  It would probably be a lot of work, which we'll just
end up removing eventually.  I'd rather just fix any formatting issues
we find and move forward.

---

From: Alexander Law <[email-masked]>
Date: Tue, 23 Aug 2016 17:23:15 +0300

Hello,
> document it or work around it.
Please consider committing attached patch. Commented-out call-template 
does nothing so we can just customize our customized templates further 
to support 1.76.
I've just performed the build with Ubuntu 13.04/docbook 1.76.1 - it works.
(In case the call-template generated something it would appear in 
bookindex.html only.)
> we find and move forward.
That work is done already and it's results are countable and observable 
differences. (See comments in the xslt.)
For example, with DSSSL we don't get a chapter TOC when the chapter 
contains only one sect1 (with XSLT we get the TOC with the one item).
We also had subtoc for sect1/refentry and sect1/simplesect, but with 
XSLT it's absent.
So if all such differences are not important, let's move forward.

Best regards,
Alexander

diff --git a/doc/src/sgml/stylesheet-speedup-xhtml.xsl b/doc/src/sgml/stylesheet-speedup-xhtml.xsl
index 8428dc5..b6df684 100644
--- a/doc/src/sgml/stylesheet-speedup-xhtml.xsl
+++ b/doc/src/sgml/stylesheet-speedup-xhtml.xsl
@@ -122,7 +122,8 @@
 
       <a>
         <xsl:apply-templates select="." mode="class.attribute"/>
-        <xsl:call-template name="id.attribute"/>
+<!--    Optimization for pgsql-docs: this call adds nothing but fails with docbook 1.76 -->
+<!--    <xsl:call-template name="id.attribute"/> -->
         <xsl:attribute name="href">
           <xsl:call-template name="href.target">
             <xsl:with-param name="object" select="$target[1]"/>
@@ -146,7 +147,8 @@
 
       <a>
         <xsl:apply-templates select="." mode="class.attribute"/>
-        <xsl:call-template name="id.attribute"/>
+<!--    Optimization for pgsql-docs: this call adds nothing but fails with docbook 1.76 -->
+<!--    <xsl:call-template name="id.attribute"/> -->
         <xsl:attribute name="href">
           <xsl:call-template name="href.target">
             <xsl:with-param name="object" select="$target[1]"/>

---

From: Peter Eisentraut <[email-masked]>
Date: Wed, 24 Aug 2016 11:12:36 -0400

> does nothing so we can just customize our customized templates further 

pushed, thanks

---

From: Alexander Law <[email-masked]>
Date: Wed, 14 Sep 2016 14:18:24 +0300

Hello, Peter.
> That work is done already and it's results are countable and 
> observable differences. (See comments in the xslt.)
Please look at the 
http://oc.postgrespro.ru/index.php/s/ttJyMDLr8Xr1HTu/download
where I have gathered together all the significant differences, that we 
have between DSSSL and XSLT outputs.
I have marked red the differences that I would consider as negative.
Let's decide which ones are acceptable and which we need to eliminate.

Best regards,
Alexander

---

From: Jürgen Purtz <[email-masked]>
Date: Wed, 14 Sep 2016 15:05:27 +0200

On 14.09.2016 13:18, Alexander Law wrote:
> where I have gathered together all the significant differences, that 
> we have between DSSSL and XSLT outputs.

Hello Alexander,

great job!

In my opinion most of the differences are not only acceptable but even 
better. Here are some addition notes:

For me the following topics are ok: 18, 19, 22, 37.

If possible we shall invest some more effort in solutions for: 1 (up + 
home not only in footer but also in header), 8, 11, 20, 30.

Topics 9 and 22 seems to be identical.

Kind regards, Jürgen

---

From: Alexander Law <[email-masked]>
Date: Wed, 14 Sep 2016 16:47:02 +0300

Hello Jürgen,
> For me the following topics are ok: 18, 19, 22, 37.
The problem with 37 is that such flat numbering present only in 
refentry. Other sections (sect1, sect2) have independent numbering.
So you can't find "Table 236", but you can find "Table 27.2. Collected 
Statistics Views" in monitoring-stats.html, for example. So it's 
inconsistent at least.
> home not only in footer but also in header), 8, 11, 20, 30.
What is marked "+" in the "XSLT alignment exists" column is already 
solved. I mean that I've developed the XSLT templates that eliminate the 
indicated differences.
I presented a patch with all the templates before (for 9.5) and adapted 
it for the master branch now.
> Topics 9 and 22 seems to be identical.
Yes, that difference required changes in two places and I duplicated the 
topic erroneously.

Best regards,
Alexander

---

From: Alvaro Herrera <[email-masked]>
Date: Wed, 14 Sep 2016 12:30:48 -0300

Jürgen Purtz wrote:

> better.

Agreed. But there are a few that merit a fix.  There are a few that look
a matter of style (XSL output looks odd), another few are not important.
But I think missing TOC for example is a problem.

1 is a customization we went great lengths to add, so it's a must fix I
think.

I think 12, 14, 15 merit more research too.

What's up with 30?

-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

---

From: Alexander Law <[email-masked]>
Date: Wed, 14 Sep 2016 18:46:20 +0300

Hello Alvaro,

> What's up with 30?

ecpg.sgml contains "<remark>The scope of the allocated descriptor is 
WHAT?.</remark>", which is printed with XSLT but ignored with DSSSL.

Maybe we can just remove such remarks. I found only two of them, other 
one in dml.sgml:

<chapter id="dml">
  <title>Data Manipulation</title>
  <remark>
   This chapter is still quite incomplete.
  </remark>

Best regards,
Alexander

---

From: Tom Lane <[email-masked]>
Date: Wed, 14 Sep 2016 11:52:29 -0400

>    This chapter is still quite incomplete.

Change them to SGML comments?  Although actually the DML one should
be removed, I think it's ancient and obsolete.

			regards, tom lane

---

From: Alvaro Herrera <[email-masked]>
Date: Wed, 14 Sep 2016 13:41:05 -0300

Alexander Law wrote:

> Maybe we can just remove such remarks.

I added Michael on CC.  Maybe he can clarify what the scope of the
descriptor is, so that we can add some proper sentence, and remove the
<remark> tag.

It's strange that the xslt prints the <remark> text, when the historical
behavior was to ignore it.  Maybe OASIS changed their mind as to what it
meant.

---

From: Alexander Law <[email-masked]>
Date: Wed, 14 Sep 2016 19:56:32 +0300

> behavior was to ignore it.  Maybe OASIS changed their mind as to what it
In fact it's controlled by show.comments variable in XSLT, which is 
defined in doc/src/sgml/stylesheet-common.xsl as:

<xsl:param name="show.comments">
   <xsl:choose>
     <xsl:when test="contains($pg.version, 'devel')">1</xsl:when>
     <xsl:otherwise>0</xsl:otherwise>
   </xsl:choose>
</xsl:param>

And it's just inconsistent with the DSSSL definition ((define 
%show-comments%         draft-mode)). So we can just ignore the 
difference. Though question that is still open since 2003 could be 
answered at the end of the day.

---

From: Alexander Law <[email-masked]>
Date: Tue, 4 Oct 2016 18:45:04 +0300

Hello,

I've modified XSL's to eliminate most undesired differences between 
`make html` and `make xslthtml` outputs. The patch attached.
See http://oc.postgrespro.ru/index.php/s/Gj2PGZ9IHUbDC5t/download 
(eliminated differences marked cyan).
What should we do next to finish with the "Port all DSSSL customizations 
to XSLT" item in our plan?

Best regards,
Alexander

index 0000000..170a21c
@@ -0,0 +1,163 @@
index 0000000..b893e9f
@@ -0,0 +1,756 @@
+<!-- Table numbering inside reference
+pgbench.html:
+Table 237. Automatic Variables
+Table 1. Automatic Variables
+<xsl:template match="figure|table|example" mode="label.markup">
+  <xsl:variable name="pchap"
+                select="(ancestor::chapter
+                        |ancestor::appendix
+                        |ancestor::article[ancestor::book])[last()]"/>
+  <xsl:variable name="prefix">
+    <xsl:if test="count($pchap) &gt; 0">
+      <xsl:apply-templates select="$pchap" mode="label.markup"/>
+        <xsl:when test="$prefix != ''">
+            <xsl:apply-templates select="$pchap" mode="label.markup"/>
+            <xsl:apply-templates select="$pchap" mode="intralabel.punctuation">
+          <xsl:number format="1" from="chapter|appendix" level="any"/>
+          <xsl:number format="1" from="book|article|reference" level="any"/>
index 631fcc4..e17a443 100644
 <xsl:include href="stylesheet-speedup-xhtml.xsl" />

 <!-- Parameters -->
@@ -20,6 +21,9 @@
 
+<xsl:param name="refentry.generate.name" select="0"/>
+<xsl:param name="refentry.generate.title" select="1"/>
+<xsl:param name="xref.with.number.and.title" select="0"></xsl:param>
 <xsl:param name="website.stylesheet" select="0"/>
 
 <xsl:param name="html.stylesheet">
@@ -50,7 +54,7 @@ preface   toc,title
 qandadiv  toc
 qandaset  toc
 reference toc,title
-sect1     toc
+sect1     toc,title
 sect2     toc
 sect3     toc
 sect4     toc

---

From: Jürgen Purtz <[email-masked]>
Date: Wed, 19 Oct 2016 11:11:47 +0200

The Docbook TC is discussing the mid-term plans for Docbook 6, see: 
https://lists.oasis-open.org/archives/docbook/201610/msg00005.html . 
Just like at Docbook 5, the normative standard will be written in 
RelaxNG+Schematron. In the past they generated dtd and xsd files out of 
RelaxNG. But for Docbook 6 they consider to drop the xsd version - the 
dtd will survive as it can be generated automatically.

* Does anybody need the xsd version in the long term? * xmllint is able 
to validate against RelaxNG.

Kind regards, Jürgen

---

From: Peter Eisentraut <[email-masked]>
Date: Tue, 8 Nov 2016 08:25:04 -0500

> Let's decide which ones are acceptable and which we need to eliminate.

Thank you for making that list.  I have a similar list that is not quite
the same, so together we'll probably find all the problems.  I have
checked both lists and most of the issues are not terribly critical.

I have now committed fixes for what I think were the major missing
usability issues: header customization and index letter links.  I would
be comfortable with switching the default build to XSLT now and work out
the remaining issues on the fly.  What do you think?

(I also have a similar list for switching the PDF build from jadetex to
fop.  We are also in pretty good shape there, but I have not finished
the evaluation fully.)

---

From: Tom Lane <[email-masked]>
Date: Tue, 08 Nov 2016 10:02:25 -0500

> the remaining issues on the fly.  What do you think?

What does that imply in terms of changing build dependencies for people
who want to build the docs?

			regards, tom lane

---

From: Peter Eisentraut <[email-masked]>
Date: Tue, 8 Nov 2016 11:34:49 -0500

> who want to build the docs?

I will write a full explanation to hackers before making any change.
But the short answer is, it's the same tools we use for building the man
pages now, so if you can run make man or make world, you're set.

---

From: Alexander Law <[email-masked]>
Date: Wed, 9 Nov 2016 13:00:19 +0300

Hello Peter,

I think it's time to switch to XSLT. We at Postgres Pro already build 
(converted to XML) and publish the docs (for version 9.6, in English and 
Russian) and we've got only one bug report related to the 
header/navigation differences.
(See https://postgrespro.com/docs/postgresql/9.6/tutorial-concepts.html 
vs https://postgrespro.com/docs/postgresql/9.5/tutorial-concepts.html).
There are other customizations that I would like to apply, but it could 
be done later.
And as we should completely move away from DSSSL to migrate to XML, I 
think the sooner we switch to XSLT, the better.

Best regards,
Alexander

---

From: Alexander Law <[email-masked]>
Date: Wed, 16 Nov 2016 14:30:32 +0300

Hello Peter,

I saw that you committed the patch to switch the html build to XSLT by 
default.
So It seems, now we can continue the move to XML.
I'd suggest to move in several steps.
Please see the attached scripts.
The main script is 7_check_conversion.sh. It performs all the conversion 
and checks whether the html output is the same.
I suggest to split conversion in three commits.
Commit#0 is for manual corrections - it replaces "<" with "&lt;" and so 
on in some sgml's and it doesn't affect the build or outputs.
It needed just for the next step - automatic conversion. These changes 
to sgml's are countable and observable.

Commit#1 performs conversion of all SGML's to make them compatible with 
XML (as much as possible). (Thanks to Jurgen for his sgml2xml.pl script.)
These changes to sgml's are massive, but they are produced 
automatically, so we need just to check the script and make sure that 
the output is the same.
After that commit we still can use SGML build.

And the last commit, commit#2 is for switching to XML. At that point 
doc/src/sgml renamed to doc/src/xml, build environment modified and 
cleaned, but changes in sgml/xml are minimal, so we can observe and 
check them.

After the commit#2 we get all our docs in XML (DocBook 4.2) and can 
build it just as we did with 'make html/man/...' before.
Maybe the commit#2 should be applied later, but commits #0 and #1 are 
not intrusive and can be applied anytime.

Best regards,
Alexander

---

From: Jürgen Purtz <[email-masked]>
Date: Wed, 16 Nov 2016 19:40:33 +0500

> The main script is 7_check_conversion.sh. It performs all the 
> conversion and checks whether the html output is the same.
> Commit#0 is for manual corrections - it replaces "<" with "&lt;" and 
> so on in some sgml's and it doesn't affect the build or outputs.
> Commit#1 performs conversion of all SGML's to make them compatible 
> with XML (as much as possible). (Thanks to Jurgen for his sgml2xml.pl 
> script.)

Hello,

I greatly welcome the next steps toward XML.

In addition to the submitted scripts I want to point out that we will 
get validation error messages if the following three things coincide: a) 
Docbook 4.2, b) use of XInclude, c) a different directory (eg: 'ref'). 
The xi:base attribute (to specify a different directory) was introduced 
into the Docbook DTD with version 4.3. Older DTDs cannot use it without 
manual changes to the DTD, please see: 
http://www.sagehill.net/docbookxsl/ValidXinclude.html. To overcome this 
shortage I suggest the use of Docbook 4.3 (or 4.5) - as a separate 
commit or implicitly with commit #2. As far as I have seen, all 
converted documents validate against 4.5.

Kind regards
Jürgen Purtz

---

From: Alexander Law <[email-masked]>
Date: Tue, 28 Feb 2017 11:55:28 +0300

Hello Peter,

> not intrusive and can be applied anytime.
I've rebased previous patches for the current "10devel" version.
Will we continue move to DocBook.XML?
Are there any obstacles that may keep us from moving forward?

Best regards,
Alexander

---

From: Jürgen Purtz <[email-masked]>
Date: Tue, 28 Feb 2017 10:50:55 +0100

Hello Alexander,

On 28.02.2017 09:55, Alexander Law wrote:
>> It needed just for the next step - automatic conversion. These 
>> changes to sgml's are countable and observable.
>>
the time gap between commit#1 and commit#2 shall be small as people may 
create - in accordance with SGML - additional empty elements and shorttags.

The attached version of sgml2xml.pl is cleaned up by elimination of 
unused variables and some modifications in the comments.

Kind regards, Jürgen

---

From: Peter Eisentraut <[email-masked]>
Date: Fri, 10 Mar 2017 21:06:00 -0500

> Are there any obstacles that may keep us from moving forward?

We still haven't gotten rid of all the DSSSL use.

---

From: Peter Eisentraut <[email-masked]>
Date: Tue, 4 Apr 2017 22:33:15 -0400

> Will we continue move to DocBook.XML?

I'm moving this to the next commit fest.  The conversion from SGML to
XML will be a theme for the PG11 development cycle.  For PG10, we have
accomplished the conversion from DSSSL to XSLT.

---

From: Peter Eisentraut <[email-masked]>
Date: Wed, 6 Sep 2017 11:54:47 -0400

> Are there any obstacles that may keep us from moving forward?

I have started working through these patches now.  I have committed the
escaping of < and & and will work through the rest slowly, to minimize
disruptions to other development.

---

From: Alexander Lakhin <[email-masked]>
Date: Fri, 8 Sep 2017 15:30:00 +0300

Hello,

Great!

I have rebased all the remaining patches and updated scripts for the 
current master (see attachment).

Best regards,
Alexander

---

From: Thomas Munro <[email-masked]>
Date: Mon, 11 Sep 2017 10:59:40 +1200

On Sat, Sep 9, 2017 at 12:30 AM, Alexander Lakhin <[email-masked]> wrote:
> I have rebased all the remaining patches and updated scripts for the current
> master (see attachment).

Hi Alexander,

In future versions of this patch set, if there is a dependency between
the patches would you mind indicating the order to apply them, perhaps
with prefixes like "0001-"?  That would be quite useful for humans who
aren't yet familiar enough with your patch set to guess the order, and
also for stupid patch testing robots:

== Fetched patches from message ID
f00bf53f-e6b5-a033-69be-0c63878f0d30%40gmail.com
== Applying on top of commit 3c435952176ae5d294b37e5963cd72ddb66edead
== Applying patches from tarball pg-doc.check.tar.bz2...
== Applying patch pg-doc.check/patches/sgml-xml/ecpg.patch...
== Applying patch pg-doc.check/patches/sgml-xml/func.patch...
== Applying patch
pg-doc.check/patches/sgml-xml/generate-errcodes-table.pl.patch...
== Applying patch pg-doc.check/patches/sgml-xml/pgtesttiming.patch...
== Applying patch pg-doc.check/patches/sgml-xml/release-10.patch...
1 out of 5 hunks FAILED -- saving rejects to file
doc/src/sgml/release-10.sgml.rej

Thanks!

-- 
Thomas Munro
http://www.enterprisedb.com

---

From: Peter Eisentraut <[email-masked]>
Date: Fri, 15 Sep 2017 10:32:45 -0400

> current master (see attachment).

So, I've been looking at this profiling stuff, to replace the marked
sections in the installation instructions.  I found the overhead of that
a bit too much for building the full documentation, so I have come up
with the attached alternative solution.  What do you think?

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 9ebfd07205254bb81487d37cbf4ea31b275b9f94 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email-masked]>
Date: Fri, 15 Sep 2017 10:17:37 -0400
Subject: [PATCH] Get rid of parameterized marked sections in SGML

Previously, we created a variant of the installation instructions for
producing the plain-text INSTALL file by marking up certain parts of
installation.sgml using SGML parameterized marked sections.  Marked
sections will not work anymore in XML, so before we can convert the
documentation to XML, we need a new approach.

DocBook provides a "profiling" feature that allows selecting content
based on attributes, which would work here.  But it imposes a noticeable
overhead when building the full documentation, and give that we recently
spent a fair amount of effort optimizing the documentation build time,
it seems sad to have to accept that.

So as an alternative, (1) we create our own mini-profiling layer that
adjusts just the text we want, and (2) assemble the pieces of content
that we want in the INSTALL file using XInclude.  That way, there is no
overhead when building the full documentation and most of the "ugly"
stuff in installation.sgml can be removed and dealt with out of line.
---
 doc/src/sgml/Makefile                |   5 +-
 doc/src/sgml/filelist.sgml           |   9 --
 doc/src/sgml/installation.sgml       | 243 +++++------------------------------
 doc/src/sgml/standalone-install.sgml |  28 ----
 doc/src/sgml/standalone-install.xml  | 167 ++++++++++++++++++++++++
 doc/src/sgml/standalone-profile.xsl  |  81 ++++++++++++
 6 files changed, 280 insertions(+), 253 deletions(-)
 delete mode 100644 doc/src/sgml/standalone-install.sgml
 create mode 100644 doc/src/sgml/standalone-install.xml
 create mode 100644 doc/src/sgml/standalone-profile.xsl

diff --git a/doc/src/sgml/Makefile b/doc/src/sgml/Makefile
index 7458ef4de2..128d827c1a 100644
--- a/doc/src/sgml/Makefile
+++ b/doc/src/sgml/Makefile
@@ -134,9 +134,8 @@ INSTALL.html: %.html : stylesheet-text.xsl %.xml
 	$(XMLLINT) --noout --valid $*.xml
 	$(XSLTPROC) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_FLAGS) $^ >$@
 
-INSTALL.xml: standalone-install.sgml installation.sgml version.sgml
-	$(OSX) $(SPFLAGS) $(SGMLINCLUDE) -x lower $(filter-out version.sgml,$^) >$@.tmp
-	$(call mangle-xml,chapter)
+INSTALL.xml: standalone-profile.xsl standalone-install.xml postgres.xml
+	$(XSLTPROC) $(XSLTPROCFLAGS) --xinclude $(wordlist 1,2,$^) >$@

 ##
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index b914086009..bb93448c37 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -191,12 +191,3 @@
 
 <!-- back matter -->
 <!ENTITY biblio     SYSTEM "biblio.sgml">
-
-<!--
- Some parts of the documentation are also source for some plain-text
- files used during installation.  To selectively ignore or include
- some parts (e.g., external xref's) when generating these files we use
- these parameter entities.  See also standalone-install.sgml.
- -->
-<!ENTITY % standalone-ignore  "INCLUDE">
-<!ENTITY % standalone-include "IGNORE">
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 12866b4bf7..17079c5fa4 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1,28 +1,26 @@
 <!-- doc/src/sgml/installation.sgml -->
 <!--
 
-Use </link> not just </> so INSTALL.html can be created without links
-to the main documentation.  Don't use <xref>; or if you must, wrap it
-in a standalone-ignore clause.
+The standalone version has some portions that are different from the version
+that is integrated into the full documentation set, in particular as regards
+links, so that INSTALL.html can be created without links to the main
+documentation.  See standalone-profile.xsl for details.
 
 -->
 
 <chapter id="installation">
- <title><![%standalone-include[<productname>PostgreSQL</>]]>
-  Installation from Source Code</title>
+ <title>Installation from Source Code</title>
 
  <indexterm zone="installation">
   <primary>installation</primary>
  </indexterm>
 
  <para>
-  This <![%standalone-include;[document]]>
-  <![%standalone-ignore;[chapter]]> describes the installation of
+  This <phrase>chapter</phrase> describes the installation of
   <productname>PostgreSQL</productname> using the source code
   distribution.  (If you are installing a pre-packaged distribution,
   such as an RPM or Debian package, ignore this
-  <![%standalone-include;[document]]>
-  <![%standalone-ignore;[chapter]]>
+  <phrase>chapter</phrase>
   and read the packager's instructions instead.)
  </para>
 
@@ -45,8 +43,7 @@ <title>Short Version</title>
 /usr/local/pgsql/bin/psql test
 </synopsis>
    The long version is the rest of this
-   <![%standalone-include;[document.]]>
-   <![%standalone-ignore;[chapter.]]>
+   <phrase>chapter</phrase>.
   </para>
  </sect1>
 
@@ -197,8 +194,7 @@ <title>Requirements</title>
       required version is <productname>Python</productname> 2.4.
       <productname>Python 3</productname> is supported if it's
       version 3.1 or later; but see
-      <![%standalone-include[the <application>PL/Python</> documentation]]>
-      <![%standalone-ignore[<xref linkend="plpython-python23">]]>
+      <xref linkend="plpython-python23">
       when using Python 3.
      </para>
 
@@ -267,9 +263,7 @@ <title>Requirements</title>
      <para>
       To build the <productname>PostgreSQL</productname> documentation,
       there is a separate set of requirements; see
-      <![%standalone-ignore;[<xref linkend="docguide-toolsets">.]]>
-      <![%standalone-include;[the main documentation's appendix on
-      documentation.]]>
+      <xref linkend="docguide-toolsets">.
      </para>
     </listitem>
    </itemizedlist>
@@ -340,7 +334,6 @@ <title>Requirements</title>
   </para>
  </sect1>
 
-<![%standalone-ignore;[
  <sect1 id="install-getsource">
   <title>Getting The Source</title>
 
@@ -369,7 +362,6 @@ <title>Getting The Source</title>
    <xref linkend="sourcerepo">.
   </para>
  </sect1>
-]]>
 
  <sect1 id="install-procedure">
   <title>Installation Procedure</title>
@@ -844,9 +836,8 @@ <title>Configuration</title>
         <para>
          Build with <acronym>LDAP</><indexterm><primary>LDAP</></>
          support for authentication and connection parameter lookup (see
-         <![%standalone-include[the documentation about client authentication
-         and libpq]]><![%standalone-ignore[<xref linkend="libpq-ldap"> and
-         <xref linkend="auth-ldap">]]> for more information). On Unix,
+         <phrase id="install-ldap-links"><xref linkend="libpq-ldap"> and
+         <xref linkend="auth-ldap"></phrase> for more information). On Unix,
          this requires the <productname>OpenLDAP</> package to be
          installed. On Windows, the default <productname>WinLDAP</>
          library is used.  <filename>configure</> will check for the required
@@ -865,8 +856,8 @@ <title>Configuration</title>
          for <application>systemd</application><indexterm><primary>systemd</primary></indexterm>
          service notifications.  This improves integration if the server binary
          is started under <application>systemd</application> but has no impact
-         otherwise<![%standalone-ignore[; see <xref linkend="server-start"> for more
-         information]]>.  <application>libsystemd</application> and the
+         otherwise<phrase condition="standalone-ignore">; see <xref linkend="server-start"> for more
+         information</phrase>.  <application>libsystemd</application> and the
          associated header files need to be installed to be able to use this
          option.
         </para>
@@ -911,8 +902,7 @@ <title>Configuration</title>
        <term><option>--with-uuid=<replaceable>LIBRARY</replaceable></option></term>
        <listitem>
         <para>
-         Build the <![%standalone-include[uuid-ossp]]>
-         <![%standalone-ignore[<xref linkend="uuid-ossp">]]> module
+         Build the <xref linkend="uuid-ossp"> module
          (which provides functions to generate UUIDs), using the specified
          UUID library.<indexterm><primary>UUID</primary></indexterm>
          <replaceable>LIBRARY</replaceable> must be one of:
@@ -979,8 +969,7 @@ <title>Configuration</title>
        <listitem>
         <para>
          Use libxslt when building the
-         <![%standalone-include[xml2]]>
-         <![%standalone-ignore[<xref linkend="xml2">]]>
+         <xref linkend="xml2">
          module.  <application>xml2</> relies on this library
          to perform XSL transformations of XML.
         </para>
@@ -1110,8 +1099,7 @@ <title>Configuration</title>
          has no support for strong random numbers on the platform.
          A source of random numbers is needed for some authentication
          protocols, as well as some routines in the
-         <![%standalone-include[pgcrypto]]>
-         <![%standalone-ignore[<xref linkend="pgcrypto">]]>
+         <xref linkend="pgcrypto">
          module. <option>--disable-strong-random</option> disables functionality that
          requires cryptographically strong random numbers, and substitutes
          a weak pseudo-random-number-generator for the generation of
@@ -1215,8 +1203,8 @@ <title>Configuration</title>
          code coverage testing instrumentation.  When run, they
          generate files in the build directory with code coverage
          metrics.
-         <![%standalone-ignore[See <xref linkend="regress-coverage">
-         for more information.]]> This option is for use only with GCC
+         <phrase condition="standalone-ignore">See <xref linkend="regress-coverage">
+         for more information.</phrase> This option is for use only with GCC
          and when doing development work.
         </para>
        </listitem>
@@ -1276,8 +1264,8 @@ <title>Configuration</title>
          </indexterm>
          Compiles <productname>PostgreSQL</productname> with support for the
          dynamic tracing tool DTrace.
-         <![%standalone-ignore[See <xref linkend="dynamic-trace">
-         for more information.]]>
+         <phrase condition="standalone-ignore">See <xref linkend="dynamic-trace">
+         for more information.</phrase>
         </para>
 
         <para>
@@ -1312,7 +1300,7 @@ <title>Configuration</title>
         <para>
          Enable tests using the Perl TAP tools.  This requires a Perl
          installation and the Perl module <literal>IPC::Run</literal>.
-         <![%standalone-ignore;[See <xref linkend="regress-tap"> for more information.]]>
+         <phrase condition="standalone-ignore">See <xref linkend="regress-tap"> for more information.</phrase>
         </para>
        </listitem>
       </varlistentry>
@@ -1469,9 +1457,7 @@ <title>Configuration</title>
          whether Python 2 or 3 is specified here (or otherwise
          implicitly chosen) determines which variant of the PL/Python
          language becomes available.  See
-         <![%standalone-include[the <application>PL/Python</>
-         documentation]]>
-         <![%standalone-ignore[<xref linkend="plpython-python23">]]>
+         <xref linkend="plpython-python23">
          for more information.
         </para>
        </listitem>
@@ -1598,10 +1584,7 @@ <title>Regression Tests</title>
 <userinput>make check</userinput>
 </screen>
     (This won't work as root; do it as an unprivileged user.)
-    <![%standalone-include[The file
-    <filename>src/test/regress/README</> and the
-    documentation contain]]>
-    <![%standalone-ignore[<xref linkend="regress"> contains]]>
+    See <xref linkend="regress"> for
     detailed information about interpreting the test results. You can
     repeat this test at any later time by issuing the same command.
    </para>
@@ -1613,8 +1596,7 @@ <title>Installing the Files</title>
    <note>
     <para>
      If you are upgrading an existing system be sure to read
-     <![%standalone-include[the documentation,]]>
-     <![%standalone-ignore[<xref linkend="upgrading">]]>
+     <xref linkend="upgrading">,
      which has instructions about upgrading a
      cluster.
     </para>
@@ -1872,167 +1854,6 @@ <title>Environment Variables</title>
   </sect2>
  </sect1>
 
-
-<![%standalone-include;[
- <sect1 id="install-getting-started">
-  <title>Getting Started</title>
-
-  <para>
-   The following is a quick summary of how to get <productname>PostgreSQL</> up and
-   running once installed. The main documentation contains more information.
-  </para>
-
-  <procedure>
-   <step>
-    <para>
-     Create a user account for the <productname>PostgreSQL</>
-     server. This is the user the server will run as. For production
-     use you should create a separate, unprivileged account
-     (<quote>postgres</> is commonly used). If you do not have root
-     access or just want to play around, your own user account is
-     enough, but running the server as root is a security risk and
-     will not work.
-<screen>
-<userinput>adduser postgres</>
-</screen>
-    </para>
-   </step>
-
-   <step>
-    <para>
-     Create a database installation with the <command>initdb</>
-     command. To run <command>initdb</> you must be logged in to your
-     <productname>PostgreSQL</> server account. It will not work as
-     root.
-<screen>
-root# <userinput>mkdir /usr/local/pgsql/data</>
-root# <userinput>chown postgres /usr/local/pgsql/data</>
-root# <userinput>su - postgres</>
-postgres$ <userinput>/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data</>
-</screen>
-    </para>
-
-    <para>
-     The <option>-D</> option specifies the location where the data
-     will be stored. You can use any path you want, it does not have
-     to be under the installation directory. Just make sure that the
-     server account can write to the directory (or create it, if it
-     doesn't already exist) before starting <command>initdb</>, as
-     illustrated here.
-    </para>
-   </step>
-
-   <step>
-    <para>
-     At this point, if you did not use the <command>initdb</> <literal>-A</>
-     option, you might want to modify <filename>pg_hba.conf</> to control
-     local access to the server before you start it.  The default is to
-     trust all local users.
-    </para>
-   </step>
-
-   <step>
-    <para>
-     The previous <command>initdb</> step should have told you how to
-     start up the database server. Do so now. The command should look
-     something like:
-<programlisting>
-/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
-</programlisting>
-     This will start the server in the foreground. To put the server
-     in the background use something like:
-<programlisting>
-nohup /usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data \
-    &lt;/dev/null &gt;&gt;server.log 2&gt;&amp;1 &lt;/dev/null &amp;
-</programlisting>
-    </para>
-
-    <para>
-     To stop a server running in the background you can type:
-<programlisting>
-kill `cat /usr/local/pgsql/data/postmaster.pid`
-</programlisting>
-    </para>
-   </step>
-
-   <step>
-    <para>
-     Create a database:
-<screen>
-<userinput>createdb testdb</>
-</screen>
-     Then enter:
-<screen>
-<userinput>psql testdb</>
-</screen>
-     to connect to that database. At the prompt you can enter SQL
-     commands and start experimenting.
-    </para>
-   </step>
-  </procedure>
- </sect1>
-
- <sect1 id="install-whatnow">
-  <title>What Now?</title>
-
-  <para>
-   <itemizedlist>
-    <listitem>
-     <para>
-      The <productname>PostgreSQL</> distribution contains a
-      comprehensive documentation set, which you should read sometime.
-      After installation, the documentation can be accessed by
-      pointing your browser to
-      <filename>/usr/local/pgsql/doc/html/index.html</>, unless you
-      changed the installation directories.
-     </para>
-
-     <para>
-      The first few chapters of the main documentation are the Tutorial,
-      which should be your first reading if you are completely new to
-      <acronym>SQL</> databases.  If you are familiar with database
-      concepts then you want to proceed with part on server
-      administration, which contains information about how to set up
-      the database server, database users, and authentication.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Usually, you will want to modify your computer so that it will
-      automatically start the database server whenever it boots. Some
-      suggestions for this are in the documentation.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Run the regression tests against the installed server (using
-      <command>make installcheck</command>). If you didn't run the
-      tests before installation, you should definitely do it now. This
-      is also explained in the documentation.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      By default, <productname>PostgreSQL</> is configured to run on
-      minimal hardware.  This allows it to start up with almost any
-      hardware configuration. The default configuration is, however,
-      not designed for optimum performance. To achieve optimum
-      performance, several server parameters must be adjusted, the two
-      most common being <varname>shared_buffers</varname> and
-      <varname>work_mem</varname>.
-      Other parameters mentioned in the documentation also affect
-      performance.
-     </para>
-    </listitem>
-   </itemizedlist>
-  </para>
- </sect1>
-]]>
-
-
  <sect1 id="supported-platforms">
   <title>Supported Platforms</title>
 
@@ -2090,9 +1911,7 @@ <title>Platform-specific Notes</title>
    regarding the installation and setup of PostgreSQL.  Be sure to
    read the installation instructions, and in
    particular <xref linkend="install-requirements"> as well.  Also,
-   check <![%standalone-include[the
-   file <filename>src/test/regress/README</> and the documentation]]>
-   <![%standalone-ignore[<xref linkend="regress">]]> regarding the
+   check <xref linkend="regress"> regarding the
    interpretation of regression test results.
   </para>
 
@@ -2443,7 +2262,7 @@ <title>Cygwin</title>
    <para>
     PostgreSQL can be built using Cygwin, a Linux-like environment for
     Windows, but that method is inferior to the native Windows build
-    <![%standalone-ignore[(see <xref linkend="install-windows">)]]> and
+    <phrase condition="standalone-ignore">(see <xref linkend="install-windows">)</phrase> and
     running a server under Cygwin is no longer recommended.
    </para>
 
@@ -2641,8 +2460,7 @@ <title>MinGW/Native Windows</title>
     Microsoft's <productname>Visual C++</productname> compiler suite.
     The MinGW build variant uses the normal build system described in
     this chapter; the Visual C++ build works completely differently
-    and is described in <![%standalone-include[the
-    documentation]]><![%standalone-ignore[<xref linkend="install-windows">]]>.
+    and is described in <xref linkend="install-windows">.
     It is a fully native build and uses no additional software like
     MinGW.  A ready-made installer is available on the main
     PostgreSQL web site.
@@ -2803,9 +2621,8 @@ <title>Compiling for Optimal Performance</title>
     <title>Using DTrace for Tracing PostgreSQL</title>
 
     <para>
-     Yes, using DTrace is possible.  See <![%standalone-include[the
-     documentation]]>
-     <![%standalone-ignore[<xref linkend="dynamic-trace">]]> for further
+     Yes, using DTrace is possible.  See
+     <xref linkend="dynamic-trace"> for further
      information.  You can also find more information in this
      article: <ulink url="https://blogs.oracle.com/robertlor/entry/user_level_dtrace_probes_in"></ulink>.
     </para>
diff --git a/doc/src/sgml/standalone-install.sgml b/doc/src/sgml/standalone-install.sgml
deleted file mode 100644
index 1942f9dc4c..0000000000
--- a/doc/src/sgml/standalone-install.sgml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- doc/src/sgml/standalone-install.sgml -->
-
-<!--
-This file helps in generating the INSTALL text file that lives in the
-top level directory of the distribution.
--->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook V4.2//EN" [
-
-<!ENTITY % version SYSTEM "version.sgml">
-%version;
-
-<!--
-The standalone version has some portions that are different from the
-version that is integrated into the full documentation set, in
-particular as regards links. The following are essentially SGML's
-equivalent of C's #ifdef and friends. The other end of this is in
-installation.sgml.
--->
-
- <!ENTITY % standalone-ignore  "IGNORE">
- <!ENTITY % standalone-include "INCLUDE">
-
-<!--
-When you're building the full documentation set, you want to flip the
-IGNORE and INCLUDE.
--->
-]>
diff --git a/doc/src/sgml/standalone-install.xml b/doc/src/sgml/standalone-install.xml
new file mode 100644
index 0000000000..49d94c5187
--- /dev/null
+++ b/doc/src/sgml/standalone-install.xml
@@ -0,0 +1,167 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+This file contains the stand-alone installation instructions that end up in
+the INSTALL file.  This document stitches together parts of the installation
+instructions in the main documentation with some material that only appears
+in the stand-alone version.
+-->
+<article id="installation">
+ <title><productname>PostgreSQL</productname> Installation from Source Code</title>
+
+ <para>
+  This document describes the installation of
+  <productname>PostgreSQL</productname> using this source code distribution.
+ </para>
+
+ <xi:include href="postgres.xml" xpointer="install-short" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+ <xi:include href="postgres.xml" xpointer="install-requirements" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+ <xi:include href="postgres.xml" xpointer="install-procedure" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+ <xi:include href="postgres.xml" xpointer="install-post" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+
+ <sect1 id="install-getting-started">
+  <title>Getting Started</title>
+
+  <para>
+   The following is a quick summary of how to get <productname>PostgreSQL</productname> up and
+   running once installed. The main documentation contains more information.
+  </para>
+
+  <procedure>
+   <step>
+    <para>
+     Create a user account for the <productname>PostgreSQL</productname>
+     server. This is the user the server will run as. For production
+     use you should create a separate, unprivileged account
+     (<quote>postgres</quote> is commonly used). If you do not have root
+     access or just want to play around, your own user account is
+     enough, but running the server as root is a security risk and
+     will not work.
+<screen><userinput>adduser postgres</userinput></screen>
+    </para>
+   </step>
+
+   <step>
+    <para>
+     Create a database installation with the <command>initdb</command>
+     command. To run <command>initdb</command> you must be logged in to your
+     <productname>PostgreSQL</productname> server account. It will not work as
+     root.
+<screen>root# <userinput>mkdir /usr/local/pgsql/data</userinput>
+root# <userinput>chown postgres /usr/local/pgsql/data</userinput>
+root# <userinput>su - postgres</userinput>
+postgres$ <userinput>/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data</userinput></screen>
+    </para>
+
+    <para>
+     The <option>-D</option> option specifies the location where the data
+     will be stored. You can use any path you want, it does not have
+     to be under the installation directory. Just make sure that the
+     server account can write to the directory (or create it, if it
+     doesn't already exist) before starting <command>initdb</command>, as
+     illustrated here.
+    </para>
+   </step>
+
+   <step>
+    <para>
+     At this point, if you did not use the <command>initdb</command> <literal>-A</literal>
+     option, you might want to modify <filename>pg_hba.conf</filename> to control
+     local access to the server before you start it.  The default is to
+     trust all local users.
+    </para>
+   </step>
+
+   <step>
+    <para>
+     The previous <command>initdb</command> step should have told you how to
+     start up the database server. Do so now. The command should look
+     something like:
+<programlisting>/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data</programlisting>
+     This will start the server in the foreground. To put the server
+     in the background use something like:
+<programlisting>nohup /usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data \
+    &lt;/dev/null &gt;&gt;server.log 2&gt;&amp;1 &lt;/dev/null &amp;</programlisting>
+    </para>
+
+    <para>
+     To stop a server running in the background you can type:
+<programlisting>kill `cat /usr/local/pgsql/data/postmaster.pid`</programlisting>
+    </para>
+   </step>
+
+   <step>
+    <para>
+     Create a database:
+<screen><userinput>createdb testdb</userinput></screen>
+     Then enter:
+<screen><userinput>psql testdb</userinput></screen>
+     to connect to that database. At the prompt you can enter SQL
+     commands and start experimenting.
+    </para>
+   </step>
+  </procedure>
+ </sect1>
+
+ <sect1 id="install-whatnow">
+  <title>What Now?</title>
+
+  <para>
+   <itemizedlist>
+    <listitem>
+     <para>
+      The <productname>PostgreSQL</productname> distribution contains a
+      comprehensive documentation set, which you should read sometime.
+      After installation, the documentation can be accessed by
+      pointing your browser to
+      <filename>/usr/local/pgsql/doc/html/index.html</filename>, unless you
+      changed the installation directories.
+     </para>
+
+     <para>
+      The first few chapters of the main documentation are the Tutorial,
+      which should be your first reading if you are completely new to
+      <acronym>SQL</acronym> databases.  If you are familiar with database
+      concepts then you want to proceed with part on server
+      administration, which contains information about how to set up
+      the database server, database users, and authentication.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Usually, you will want to modify your computer so that it will
+      automatically start the database server whenever it boots. Some
+      suggestions for this are in the documentation.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Run the regression tests against the installed server (using
+      <command>make installcheck</command>). If you didn't run the
+      tests before installation, you should definitely do it now. This
+      is also explained in the documentation.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      By default, <productname>PostgreSQL</productname> is configured to run on
+      minimal hardware.  This allows it to start up with almost any
+      hardware configuration. The default configuration is, however,
+      not designed for optimum performance. To achieve optimum
+      performance, several server parameters must be adjusted, the two
+      most common being <varname>shared_buffers</varname> and
+      <varname>work_mem</varname>.
+      Other parameters mentioned in the documentation also affect
+      performance.
+     </para>
+    </listitem>
+   </itemizedlist>
+  </para>
+ </sect1>
+
+ <xi:include href="postgres.xml" xpointer="supported-platforms" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+ <xi:include href="postgres.xml" xpointer="installation-platform-notes" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+</article>
diff --git a/doc/src/sgml/standalone-profile.xsl b/doc/src/sgml/standalone-profile.xsl
new file mode 100644
index 0000000000..ff464c1654
--- /dev/null
+++ b/doc/src/sgml/standalone-profile.xsl
@@ -0,0 +1,81 @@
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0">
+
+<!--
+This is a preprocessing layer to convert the installation instructions into a
+variant without links and references to the main documentation.
+
+- To omit something in the stand-alone INSTALL file, give the element a
+  condition="standalone-ignore" attribute.
+
+- If there is no element that exactly covers what you want to change, wrap it
+  in a <phrase> element, which otherwise does nothing.
+
+- Otherwise, write a custom rule below.
+-->
+
+<xsl:output
+    doctype-public="-//OASIS//DTD DocBook XML V4.2//EN"
+    doctype-system="http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"/>
+
+<!-- copy everything by default -->
+
+<xsl:template match="@*|node()">
+  <xsl:copy>
+    <xsl:apply-templates select="@*|node()" />
+  </xsl:copy>
+</xsl:template>
+
+<!-- particular conversions -->
+
+<xsl:template match="*[@condition='standalone-ignore']">
+</xsl:template>
+
+<xsl:template match="phrase/text()['chapter']">
+  <xsl:text>document</xsl:text>
+</xsl:template>
+
+<xsl:template match="phrase[@id='install-ldap-links']">
+  <xsl:text>the documentation about client authentication and libpq</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='docguide-toolsets']">
+  <xsl:text>the main documentation's appendix on documentation</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='dynamic-trace']">
+  <xsl:text>the documentation</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='install-windows']">
+  <xsl:text>the documentation</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='pgcrypto']">
+  <xsl:text>pgcrypto</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='plpython-python23']">
+  <xsl:text>the </xsl:text><application>PL/Python</application><xsl:text> documentation</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='regress']">
+  <xsl:text>the file </xsl:text>
+  <filename>src/test/regress/README</filename>
+  <xsl:text> and the documentation</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='upgrading']">
+  <xsl:text>the documentation</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='uuid-ossp']">
+  <xsl:text>uuid-ossp</xsl:text>
+</xsl:template>
+
+<xsl:template match="xref[@linkend='xml2']">
+  <xsl:text>xml2</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
-- 
2.11.0 (Apple Git-81)

---

From: Jürgen Purtz <[email-masked]>
Date: Fri, 15 Sep 2017 23:54:57 +0500

> with the attached alternative solution.  What do you think?

I'm not happy with the 'particular conversions'-part of 
'standalone-profile.xsl'. It applies subsequent modifications, which are 
in not very intuitive to a reader, eg:

<xsl:template match="phrase[@id='install-ldap-links']">
   <xsl:text>the documentation about client authentication and 
libpq</xsl:text>
</xsl:template>

This approach spreads the intended text over two very different files 
(in this example: 'installation.xml' and 'standalone-profile.xsl').

My suggestion is to keep the source code in one file in the same manner 
as with the SGML standalone-include/standalone-ignore mechanism. A 
*generic* xsl file shall create the extended output similar to 
'standalone-profile.xsl'.

installation.xml:

support for authentication and connection parameter lookup (see
<phrase condition="standalone">the documentation about client 
authentication and libpq</phrase>
<phrase condition="default"><xref linkend="libpq-ldap"/> and<xref 
linkend="auth-ldap"/></phrase>
for more information). On Unix,
...

collectAll.xsl (similar to standalone-profile.xsl):

   <!-- parameters and variables -->
   <xsl:param name="pg.Standalone" select="'default'"/>
   <!-- <xsl:param name="pg.Standalone" select="'standalone'"/> -->

   <!-- Process all nodes  -->
   <xsl:template match="*|@*|text()|processing-instruction()|comment()">
     <xsl:choose>
       <xsl:when test="(not (@condition) or @condition=$pg.Standalone )">
         <!-- copy nodes without a 'condition' attribute and such nodes, 
where 'condition' meets the given criteria  -->
         <xsl:copy>
           <xsl:apply-templates 
select="*|@*|text()|processing-instruction()|comment()"/>
         </xsl:copy>
       </xsl:when>
     </xsl:choose>
   </xsl:template>

I'm sorry that I actually cannot deliver a patch because I'm abroad and 
have limited resources (but many challenges). But I hope that the idea 
gets clear. The attached collectAll.xsl file contains a more complex 
solution for the case that we have to deal with more than one 
include/ignore type, eg: index-generating.

---

From: Peter Eisentraut <[email-masked]>
Date: Mon, 18 Sep 2017 09:57:02 -0400

> for more information). On Unix,

That is what the standard DocBook profiling system does.  But that has
the disadvantage of imposing a performance penalty on building the
documentation.  Unless you have a way around that that I'm not seeing.

---

From: Alexander Lakhin <[email-masked]>
Date: Mon, 18 Sep 2017 17:38:27 +0300

Hello,
>> with the attached alternative solution.  What do you think?
Peter, can you show what performance drop you see with the profiling 
(e.g. for HTML)?
I get the following numbers:
1. make html with profiling (import profile-chunk.xsl in stylesheet.xsl):
85.98user 0.76system 1:29.85elapsed

2. make html without profiling (import chunk.xsl in stylesheet.xsl):
77.36user 0.62system 1:21.28elapsed

3. Separate profiling (performed before making epub, as dbtoepub doesn't 
support profiling)
8.52user 0.22system 0:10.31elapsed

So I get ~10% performance drop when making html. Are you concerned about 
the same overhead?
I would choose some standard way to have separate content in the same 
file, but if the overhead is not acceptable, and we're not going to 
extend the profiling usage, then we need to invent something that will 
complicate XML-related processing (I think about translation but the 
other issues are possible too).

> 'standalone-profile.xsl'. It applies subsequent modifications, which 
> are in not very intuitive to a reader, eg:
>
> My suggestion is to keep the source code in one file in the same 
> manner as with the SGML standalone-include/standalone-ignore 
> mechanism. A *generic* xsl file shall create the extended output 
> similar to 'standalone-profile.xsl'.
>
Jürgen, this approach implemented by applying profiling.xsl in Makefile 
(for make postgres.epub). (See Makefile in 
https://www.postgresql.org/message-id/attachment/54854/pg-doc.check.tar.bz2)

Best regards,
Alexander

---

From: Peter Eisentraut <[email-masked]>
Date: Tue, 19 Sep 2017 16:05:35 -0400

> So I get ~10% performance drop when making html. Are you concerned about

Yeah, that's about what I see.

> other issues are possible too).

It's only for the INSTALL file and won't get used anywhere else, so I
think it's OK to have a bit of an ad-hoc system.

> https://www.postgresql.org/message-id/attachment/54854/pg-doc.check.tar.bz2)

I hadn't even looked at that yet, but that kind of supports my point.
Injecting the profiling layer everywhere is going to be annoying.

---

From: Alexander Lakhin <[email-masked]>
Date: Wed, 20 Sep 2017 16:00:00 +0300

Hello Peter,
> think it's OK to have a bit of an ad-hoc system.
Well, then I would suggest to place all the extra content in the 
installation-single.xsl file and to add all the alternate text to 
installation.xml.
I would like to place such alternate text in an attribute 
"standalonetext" or alike, but DocBook 4.x doesn't allow for extra 
attributes, so we need to choose from: 
http://tdg.docbook.org/tdg/4.5/ref-elements.html#common.attributes
So I decided to make alternative use of xreflabel attribute. (I believe 
that we could find something more appropriate after migrating from 
Docbook 4.2 to 5.x).)

Please see patches/xml/installation.patch in the attachment (or 
installation.xml in doc/src/xml after ) for an example.
Makefile (in patches/xml/) is adjusted for the new approach too.
(Main output is slightly changed after switching from 
"profile-chunk.xsl" to "chunk.xsl", I'll fix it later if we choose this 
way.)
(Archive in the attachment is packed twice to avoid the automatic patch 
checking...)

Best regards,
Alexander

---

From: Peter Eisentraut <[email-masked]>
Date: Wed, 27 Sep 2017 11:38:31 -0400

> that we could find something more appropriate after migrating from 

Yeah, but that's a bit of a hack isn't it?  I also don't see anything in
DocBook 5 that indicates to me that we could get rid of that hack then.

In the interest of moving things along, I have committed my patch and
will continue working on the rest of the patch set.

Improvements are welcome and can be submitted separately, but I think
it's hardly worth it because this stuff changes so rarely.

---

From: Alexander Lakhin <[email-masked]>
Date: Wed, 27 Sep 2017 19:11:29 +0300

Hello,
> DocBook 5 that indicates to me that we could get rid of that hack then.
I found a more appropriate way for using an extra attribute:
http://www.sagehill.net/docbookxsl/AddProfileAtt.htm
I've tested it with "standalone" attribute and it works (for Docbook 4.2).
May be it will decrease hackiness level of the solution?
If it's not too late I could prepare a new patchset today.
> it's hardly worth it because this stuff changes so rarely.
But with such approach we should translate that .xsl too and it seems 
rather strange, isn't it?

------
Alexander Lakhin

---

From: Alexander Lakhin <[email-masked]>
Date: Wed, 27 Sep 2017 22:51:28 +0300

> rather strange, isn't it?
Improved patch attached.

---

From: Alexander Lakhin <[email-masked]>
Date: Thu, 16 Nov 2017 09:00:28 +0300

Hello Peter,

16.11.2017 00:06, Peter Eisentraut wrote:
> Here is the final patch set for the conversion.
Great!

I have some questions.
1. Can you share the exact scripts you use to generate 0002?
(We transform the documentation to xml since 9.6 on-fly so it would be 
nice to adjust our scripts for previous versions too.)
2. Will you rename *.sgml to *.xml and move src/sgml to src/xml?
3. And I still think that hard-coding references and replacements in the 
standalone-profile is not good. Are you going to apply less hackish 
approach?
(See 
https://www.postgresql.org/message-id/b4fd6932-8d44-3210-48ab-bbc393bf9a23%40gmail.com 
, patches/xml/installation.patch and patches/xml/installation-single.xsl)
4. BTW, when making postgres-A4.pdf, I get
[WARN] FOUserAgent - Destination: Unresolved ID reference 
"ecpg-type-timestamp-date" found.
It can be fixed by moving the id from the title tag to sect4:
-    <sect4>
-     <title id="ecpg-type-timestamp-date">timestamp, date</title>
+    <sect4 id="ecpg-type-timestamp-date">
+     <title>timestamp, date</title>
I wonder, what were the reasons to set id for the title tag?

Best regards,
------
Alexander Lakhin

---

From: Peter Eisentraut <[email-masked]>
Date: Sat, 18 Nov 2017 12:24:38 -0500

> 1. Can you share the exact scripts you use to generate 0002?

I used the script you (or Jürgen) provided.

> 2. Will you rename *.sgml to *.xml and move src/sgml to src/xml?

Not right now, but we should have that discussion at some point over the
next few months.

> , patches/xml/installation.patch and patches/xml/installation-single.xsl)

The patches you send me are very confusing.  If you can send me a
separate patch of what you have in mind and why and so on, we can
consider it separately, but right now I don't have much interest in
revisiting this.  What is committed works well, stays out of the way,
and causes no problems AFAICT.

> I wonder, what were the reasons to set id for the title tag?

In some cases the ids on the title tags were necessary for the DSSSL
stylesheets.  They can be removed now with some care.  I have some
partial patches for that.

These particular warnings seem harmless.  I have found the following
reference:
<https://lists.oasis-open.org/archives/docbook-apps/201510/msg00052.html>

But I see the same warnings in the PG10 build, so this does not appear
to be a regression from the XML conversion.

---

From: Peter Eisentraut <[email-masked]>
Date: Thu, 23 Nov 2017 09:53:35 -0500

> Here is the final patch set for the conversion.

I have committed this.

---

From: Alexander Lakhin <[email-masked]>
Date: Sat, 25 Nov 2017 08:50:30 +0300

Hello,
>> Here is the final patch set for the conversion. 
Great! Thank you for your work!
And in light of possible need to convert to xml older branches too, 
maybe we should simplify INSTALL now.
Please, consider applying the attached patch. It produces the same 
INSTALL and is much better in the following aspects.

1. All the INSTALL content is placed in two files (installation.sgml and 
installation-single.xsl) instead of three (installation.sgml, 
standalone-install.xml, standalone-profile.xsl).
2. There are no unreadable and untranslatable (in context) constructions 
such as
<xsl:template match="xref[@linkend='plpython-python23']">
   <xsl:text>the 
</xsl:text><application>PL/Python</application><xsl:text> 
documentation</xsl:text>
</xsl:template>
(Sometimes translators need to replace larger fragments.)
3. It uses only XSLT (which we use already), no xi:include.
4. It doesn't generate complete postgres.sgml to process only the 
installation section.

I understand that it will take some time to review it, but I think it's 
justified by the portability and supportability reasons.

Best regards,

------
Alexander Lakhin
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/doc/src/sgml/Makefile b/doc/src/sgml/Makefile
index f122b41..0cf3afe 100644
--- a/doc/src/sgml/Makefile
+++ b/doc/src/sgml/Makefile
@@ -111,13 +111,8 @@ LYNX = lynx
 INSTALL: % : %.html
 	$(PERL) -p -e 's,<h(1|2) class="title",<h\1 align=center,g' $< | LC_ALL=en_US.ISO8859-1 $(LYNX) -force_html -dump -nolist -stdin | $(ICONV) -f latin1 -t us-ascii//TRANSLIT > $@
 
-INSTALL.html: %.html : stylesheet-text.xsl %.xml
-	$(XMLLINT) --noout --valid $*.xml
-	$(XSLTPROC) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_FLAGS) $^ >$@
-
-INSTALL.xml: standalone-profile.xsl standalone-install.xml postgres.sgml $(ALLSGML)
-	$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) --xinclude $(wordlist 1,2,$^) >$@
-
+INSTALL.html: installation.sgml installation-single.xsl stylesheet-text.xsl
+	sed -e "s/&version;/$(VERSION)/" $< | $(XSLTPROC) $(XSLTPROCFLAGS) $(word 2,$^) - | $(XSLTPROC) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_FLAGS) $(word 3,$^) - >$@
 
 ##
 ## HTML
diff --git a/doc/src/sgml/installation-single.xsl b/doc/src/sgml/installation-single.xsl
new file mode 100644
index 0000000..d8f45b5
--- /dev/null
+++ b/doc/src/sgml/installation-single.xsl
@@ -0,0 +1,202 @@
+<?xml version='1.0'?>
+<!DOCTYPE xsl:stylesheet [
+<!ENTITY % version SYSTEM "version.sgml">
+%version;
+]>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0">
+
+<!--
+This is a preprocessing layer to convert the installation instructions into a
+variant without links and references to the main documentation.
+
+- To include some section from installation.sgml,
+  use the <xsl:apply-templates select="//*[@id='{section-id}']"> construction.
+
+
+- To omit or replace something in the stand-alone INSTALL file,
+  give the element (maybe wrap a plain text in <phrase>)
+  in installation.sgml a standalonetext="..." attribute.
+
+-->
+
+<xsl:output
+    doctype-public="-//OASIS//DTD DocBook XML V4.2//EN"
+    doctype-system="http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"/>
+
+<xsl:template match="@*|node()">
+  <xsl:copy>
+    <xsl:apply-templates select="@*|node()" />
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match="/">
+
+<article id="installation">
+ <title><productname>PostgreSQL</productname> Installation from Source Code</title>
+
+ <para>
+  This document describes the installation of
+  <productname>PostgreSQL</productname> using this source code distribution.
+ </para>
+
+ <xsl:apply-templates select="//*[@id='install-short']"/>
+ <xsl:apply-templates select="//*[@id='install-requirements']"/>
+ <xsl:apply-templates select="//*[@id='install-procedure']"/>
+ <xsl:apply-templates select="//*[@id='install-post']"/>
+
+ <sect1 id="install-getting-started">
+  <title>Getting Started</title>
+
+  <para>
+   The following is a quick summary of how to get <productname>PostgreSQL</productname> up and
+   running once installed. The main documentation contains more information.
+  </para>
+
+  <procedure>
+   <step>
+    <para>
+     Create a user account for the <productname>PostgreSQL</productname>
+     server. This is the user the server will run as. For production
+     use you should create a separate, unprivileged account
+     (<quote>postgres</quote> is commonly used). If you do not have root
+     access or just want to play around, your own user account is
+     enough, but running the server as root is a security risk and
+     will not work.
+<screen><userinput>adduser postgres</userinput></screen>
+    </para>
+   </step>
+
+   <step>
+    <para>
+     Create a database installation with the <command>initdb</command>
+     command. To run <command>initdb</command> you must be logged in to your
+     <productname>PostgreSQL</productname> server account. It will not work as
+     root.
+<screen>root# <userinput>mkdir /usr/local/pgsql/data</userinput>
+root# <userinput>chown postgres /usr/local/pgsql/data</userinput>
+root# <userinput>su - postgres</userinput>
+postgres$ <userinput>/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data</userinput></screen>
+    </para>
+
+    <para>
+     The <option>-D</option> option specifies the location where the data
+     will be stored. You can use any path you want, it does not have
+     to be under the installation directory. Just make sure that the
+     server account can write to the directory (or create it, if it
+     doesn't already exist) before starting <command>initdb</command>, as
+     illustrated here.
+    </para>
+   </step>
+
+   <step>
+    <para>
+     At this point, if you did not use the <command>initdb</command>&#160;<literal>-A</literal>
+     option, you might want to modify <filename>pg_hba.conf</filename> to control
+     local access to the server before you start it.  The default is to
+     trust all local users.
+    </para>
+   </step>
+
+   <step>
+    <para>
+     The previous <command>initdb</command> step should have told you how to
+     start up the database server. Do so now. The command should look
+     something like:
+<programlisting>/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data</programlisting>
+     This will start the server in the foreground. To put the server
+     in the background use something like:
+<programlisting>nohup /usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data \
+    &lt;/dev/null &gt;&gt;server.log 2&gt;&amp;1 &lt;/dev/null &amp;</programlisting>
+    </para>
+
+    <para>
+     To stop a server running in the background you can type:
+<programlisting>kill `cat /usr/local/pgsql/data/postmaster.pid`</programlisting>
+    </para>
+   </step>
+
+   <step>
+    <para>
+     Create a database:
+<screen><userinput>createdb testdb</userinput></screen>
+     Then enter:
+<screen><userinput>psql testdb</userinput></screen>
+     to connect to that database. At the prompt you can enter SQL
+     commands and start experimenting.
+    </para>
+   </step>
+  </procedure>
+ </sect1>
+
+ <sect1 id="install-whatnow">
+  <title>What Now?</title>
+
+  <para>
+   <itemizedlist>
+    <listitem>
+     <para>
+      The <productname>PostgreSQL</productname> distribution contains a
+      comprehensive documentation set, which you should read sometime.
+      After installation, the documentation can be accessed by
+      pointing your browser to
+      <filename>/usr/local/pgsql/doc/html/index.html</filename>, unless you
+      changed the installation directories.
+     </para>
+
+     <para>
+      The first few chapters of the main documentation are the Tutorial,
+      which should be your first reading if you are completely new to
+      <acronym>SQL</acronym> databases.  If you are familiar with database
+      concepts then you want to proceed with part on server
+      administration, which contains information about how to set up
+      the database server, database users, and authentication.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Usually, you will want to modify your computer so that it will
+      automatically start the database server whenever it boots. Some
+      suggestions for this are in the documentation.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Run the regression tests against the installed server (using
+      <command>make installcheck</command>). If you didn't run the
+      tests before installation, you should definitely do it now. This
+      is also explained in the documentation.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      By default, <productname>PostgreSQL</productname> is configured to run on
+      minimal hardware.  This allows it to start up with almost any
+      hardware configuration. The default configuration is, however,
+      not designed for optimum performance. To achieve optimum
+      performance, several server parameters must be adjusted, the two
+      most common being <varname>shared_buffers</varname> and
+      <varname>work_mem</varname>.
+      Other parameters mentioned in the documentation also affect
+      performance.
+     </para>
+    </listitem>
+   </itemizedlist>
+  </para>
+ </sect1>
+
+ <xsl:apply-templates select="//*[@id='supported-platforms']"/>
+ <xsl:apply-templates select="//*[@id='installation-platform-notes']"/>
+
+</article>
+</xsl:template>
+
+<xsl:template match="*[@standalonetext]">
+  <xsl:value-of select="@standalonetext" />
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index a922819..1ddf105 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -4,22 +4,24 @@
 The standalone version has some portions that are different from the version
 that is integrated into the full documentation set, in particular as regards
 links, so that INSTALL.html can be created without links to the main
-documentation.  See standalone-profile.xsl for details.
+documentation.  See installation-single.xsl for details.
 
 -->
 
 <chapter id="installation">
- <title>Installation from Source Code</title>
+ <title><phrase standalonetext="PostgreSQL"></phrase>
+  Installation from Source Code</title>

  <para>
-  This chapter describes the installation of
+  This <phrase standalonetext="document">chapter</phrase> describes the installation of
   <productname>PostgreSQL</productname> using the source code
   distribution.  (If you are installing a pre-packaged distribution,
-  such as an RPM or Debian package, ignore this chapter
+  such as an RPM or Debian package, ignore this
+  <phrase standalonetext="document">chapter</phrase>
   and read the packager's instructions instead.)
  </para>
 
@@ -42,7 +44,7 @@ su - postgres
 /usr/local/pgsql/bin/psql test
 </synopsis>
    The long version is the rest of this
-   <phrase>chapter</phrase>.
+   <phrase standalonetext="document">chapter</phrase>.
   </para>
  </sect1>
 
@@ -193,7 +195,7 @@ su - postgres
       required version is <productname>Python</productname> 2.4.
       <productname>Python 3</productname> is supported if it's
       version 3.1 or later; but see
-      <xref linkend="plpython-python23"/>
+      <xref standalonetext="the PL/Python documentation" linkend="plpython-python23"/>
       when using Python 3.
      </para>
 
@@ -262,7 +264,8 @@ su - postgres
      <para>
       To build the <productname>PostgreSQL</productname> documentation,
       there is a separate set of requirements; see
-      <xref linkend="docguide-toolsets"/>.
+      <xref standalonetext="the main documentation's appendix on documentation"
+            linkend="docguide-toolsets"/>.
      </para>
     </listitem>
    </itemizedlist>
@@ -835,8 +838,8 @@ su - postgres
         <para>
          Build with <acronym>LDAP</acronym><indexterm><primary>LDAP</primary></indexterm>
          support for authentication and connection parameter lookup (see
-         <phrase id="install-ldap-links"><xref linkend="libpq-ldap"/> and
-         <xref linkend="auth-ldap"/></phrase> for more information). On Unix,
+         <phrase standalonetext="the documentation about client authentication and libpq">
+         <xref linkend="libpq-ldap"/> and <xref linkend="auth-ldap"/></phrase> for more information). On Unix,
          this requires the <productname>OpenLDAP</productname> package to be
          installed. On Windows, the default <productname>WinLDAP</productname>
          library is used.  <filename>configure</filename> will check for the required
@@ -855,7 +858,7 @@ su - postgres
          for <application>systemd</application><indexterm><primary>systemd</primary></indexterm>
          service notifications.  This improves integration if the server binary
          is started under <application>systemd</application> but has no impact
-         otherwise<phrase condition="standalone-ignore">; see <xref linkend="server-start"/> for more
+         otherwise<phrase standalonetext="">; see <xref linkend="server-start"/> for more
          information</phrase>.  <application>libsystemd</application> and the
          associated header files need to be installed to be able to use this
          option.
@@ -901,7 +904,7 @@ su - postgres
        <term><option>--with-uuid=<replaceable>LIBRARY</replaceable></option></term>
        <listitem>
         <para>
-         Build the <xref linkend="uuid-ossp"/> module
+         Build the <xref standalonetext="uuid-ossp" linkend="uuid-ossp"/> module
          (which provides functions to generate UUIDs), using the specified
          UUID library.<indexterm><primary>UUID</primary></indexterm>
          <replaceable>LIBRARY</replaceable> must be one of:
@@ -968,7 +971,7 @@ su - postgres
        <listitem>
         <para>
          Use libxslt when building the
-         <xref linkend="xml2"/>
+         <xref standalonetext="xml2" linkend="xml2"/>
          module.  <application>xml2</application> relies on this library
          to perform XSL transformations of XML.
         </para>
@@ -1084,7 +1087,7 @@ su - postgres
          has no support for strong random numbers on the platform.
          A source of random numbers is needed for some authentication
          protocols, as well as some routines in the
-         <xref linkend="pgcrypto"/>
+         <xref standalonetext="pgcrypto" linkend="pgcrypto"/>
          module. <option>--disable-strong-random</option> disables functionality that
          requires cryptographically strong random numbers, and substitutes
          a weak pseudo-random-number-generator for the generation of
@@ -1188,7 +1191,7 @@ su - postgres
          code coverage testing instrumentation.  When run, they
          generate files in the build directory with code coverage
          metrics.
-         <phrase condition="standalone-ignore">See <xref linkend="regress-coverage"/>
+         <phrase standalonetext="">See <xref linkend="regress-coverage"/>
          for more information.</phrase> This option is for use only with GCC
          and when doing development work.
         </para>
@@ -1249,7 +1252,7 @@ su - postgres
          </indexterm>
          Compiles <productname>PostgreSQL</productname> with support for the
          dynamic tracing tool DTrace.
-         <phrase condition="standalone-ignore">See <xref linkend="dynamic-trace"/>
+         <phrase standalonetext="">See <xref linkend="dynamic-trace"/>
          for more information.</phrase>
         </para>
 
@@ -1285,7 +1288,7 @@ su - postgres
         <para>
          Enable tests using the Perl TAP tools.  This requires a Perl
          installation and the Perl module <literal>IPC::Run</literal>.
-         <phrase condition="standalone-ignore">See <xref linkend="regress-tap"/> for more information.</phrase>
+         <phrase standalonetext="">See <xref linkend="regress-tap"/> for more information.</phrase>
         </para>
        </listitem>
       </varlistentry>
@@ -1442,7 +1445,7 @@ su - postgres
          whether Python 2 or 3 is specified here (or otherwise
          implicitly chosen) determines which variant of the PL/Python
          language becomes available.  See
-         <xref linkend="plpython-python23"/>
+         <xref standalonetext="the PL/Python documentation" linkend="plpython-python23"/>
          for more information.
         </para>
        </listitem>
@@ -1569,7 +1572,8 @@ PostgreSQL, contrib, and documentation successfully made. Ready to install.
 <userinput>make check</userinput>
 </screen>
     (This won't work as root; do it as an unprivileged user.)
-    See <xref linkend="regress"/> for
+    <phrase standalonetext="See the file &quot;src/test/regress/README&quot; and the documentation for">
+    <xref linkend="regress"/> contains</phrase>
     detailed information about interpreting the test results. You can
     repeat this test at any later time by issuing the same command.
    </para>
@@ -1581,7 +1585,7 @@ PostgreSQL, contrib, and documentation successfully made. Ready to install.
    <note>
     <para>
      If you are upgrading an existing system be sure to read
-     <xref linkend="upgrading"/>,
+     <xref standalonetext="the documentation" linkend="upgrading"/>,
      which has instructions about upgrading a
      cluster.
     </para>
@@ -1895,9 +1899,9 @@ export MANPATH
    This section documents additional platform-specific issues
    regarding the installation and setup of PostgreSQL.  Be sure to
    read the installation instructions, and in
-   particular <xref linkend="install-requirements"/> as well.  Also,
-   check <xref linkend="regress"/> regarding the
-   interpretation of regression test results.
+   particular <xref linkend="install-requirements"/> as well.  Also, check
+   <xref standalonetext="the file &quot;src/test/regress/README&quot; and the documentation" linkend="regress"/>
+   regarding the interpretation of regression test results.
   </para>
 
   <para>
@@ -2247,7 +2251,7 @@ ERROR:  could not load library "/opt/dbs/pgsql/lib/plperl.so": Bad address
    <para>
     PostgreSQL can be built using Cygwin, a Linux-like environment for
     Windows, but that method is inferior to the native Windows build
-    <phrase condition="standalone-ignore">(see <xref linkend="install-windows"/>)</phrase> and
+    <phrase standalonetext="">(see <xref linkend="install-windows"/>)</phrase> and
     running a server under Cygwin is no longer recommended.
    </para>
 
@@ -2441,7 +2445,7 @@ PHSS_30849  s700_800 u2comp/be/plugin library Patch
     Microsoft's <productname>Visual C++</productname> compiler suite.
     The MinGW build variant uses the normal build system described in
     this chapter; the Visual C++ build works completely differently
-    and is described in <xref linkend="install-windows"/>.
+    and is described in <xref standalonetext="the documentation" linkend="install-windows"/>.
     It is a fully native build and uses no additional software like
     MinGW.  A ready-made installer is available on the main
     PostgreSQL web site.
@@ -2602,8 +2606,9 @@ LIBOBJS = snprintf.o
     <title>Using DTrace for Tracing PostgreSQL</title>
 
     <para>
-     Yes, using DTrace is possible.  See <xref linkend="dynamic-trace"/> for
-     further information.
+     Yes, using DTrace is possible.  See
+     <xref standalonetext="the documentation" linkend="dynamic-trace"/>
+     for further information.
     </para>
 
     <para>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 041afdb..8ae4754 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -11,6 +11,7 @@
 
 <!ENTITY reference  SYSTEM "reference.sgml">
 
+<!ENTITY % local.effectivity.attrib "standalonetext CDATA #IMPLIED">
 ]>
 
 <book id="postgres">
diff --git a/doc/src/sgml/standalone-install.xml b/doc/src/sgml/standalone-install.xml
deleted file mode 100644
index 62582ef..0000000
--- a/doc/src/sgml/standalone-install.xml
+++ /dev/null
@@ -1,167 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-This file contains the stand-alone installation instructions that end up in
-the INSTALL file.  This document stitches together parts of the installation
-instructions in the main documentation with some material that only appears
-in the stand-alone version.
--->
-<article id="installation">
- <title><productname>PostgreSQL</productname> Installation from Source Code</title>
-
- <para>
-  This document describes the installation of
-  <productname>PostgreSQL</productname> using this source code distribution.
- </para>
-
- <xi:include href="postgres.sgml" xpointer="install-short" xmlns:xi="http://www.w3.org/2001/XInclude"/>
- <xi:include href="postgres.sgml" xpointer="install-requirements" xmlns:xi="http://www.w3.org/2001/XInclude"/>
- <xi:include href="postgres.sgml" xpointer="install-procedure" xmlns:xi="http://www.w3.org/2001/XInclude"/>
- <xi:include href="postgres.sgml" xpointer="install-post" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-
- <sect1 id="install-getting-started">
-  <title>Getting Started</title>
-
-  <para>
-   The following is a quick summary of how to get <productname>PostgreSQL</productname> up and
-   running once installed. The main documentation contains more information.
-  </para>
-
-  <procedure>
-   <step>
-    <para>
-     Create a user account for the <productname>PostgreSQL</productname>
-     server. This is the user the server will run as. For production
-     use you should create a separate, unprivileged account
-     (<quote>postgres</quote> is commonly used). If you do not have root
-     access or just want to play around, your own user account is
-     enough, but running the server as root is a security risk and
-     will not work.
-<screen><userinput>adduser postgres</userinput></screen>
-    </para>
-   </step>
-
-   <step>
-    <para>
-     Create a database installation with the <command>initdb</command>
-     command. To run <command>initdb</command> you must be logged in to your
-     <productname>PostgreSQL</productname> server account. It will not work as
-     root.
-<screen>root# <userinput>mkdir /usr/local/pgsql/data</userinput>
-root# <userinput>chown postgres /usr/local/pgsql/data</userinput>
-root# <userinput>su - postgres</userinput>
-postgres$ <userinput>/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data</userinput></screen>
-    </para>
-
-    <para>
-     The <option>-D</option> option specifies the location where the data
-     will be stored. You can use any path you want, it does not have
-     to be under the installation directory. Just make sure that the
-     server account can write to the directory (or create it, if it
-     doesn't already exist) before starting <command>initdb</command>, as
-     illustrated here.
-    </para>
-   </step>
-
-   <step>
-    <para>
-     At this point, if you did not use the <command>initdb</command> <literal>-A</literal>
-     option, you might want to modify <filename>pg_hba.conf</filename> to control
-     local access to the server before you start it.  The default is to
-     trust all local users.
-    </para>
-   </step>
-
-   <step>
-    <para>
-     The previous <command>initdb</command> step should have told you how to
-     start up the database server. Do so now. The command should look
-     something like:
-<programlisting>/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data</programlisting>
-     This will start the server in the foreground. To put the server
-     in the background use something like:
-<programlisting>nohup /usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data \
-    &lt;/dev/null &gt;&gt;server.log 2&gt;&amp;1 &lt;/dev/null &amp;</programlisting>
-    </para>
-
-    <para>
-     To stop a server running in the background you can type:
-<programlisting>kill `cat /usr/local/pgsql/data/postmaster.pid`</programlisting>
-    </para>
-   </step>
-
-   <step>
-    <para>
-     Create a database:
-<screen><userinput>createdb testdb</userinput></screen>
-     Then enter:
-<screen><userinput>psql testdb</userinput></screen>
-     to connect to that database. At the prompt you can enter SQL
-     commands and start experimenting.
-    </para>
-   </step>
-  </procedure>
- </sect1>
-
- <sect1 id="install-whatnow">
-  <title>What Now?</title>
-
-  <para>
-   <itemizedlist>
-    <listitem>
-     <para>
-      The <productname>PostgreSQL</productname> distribution contains a
-      comprehensive documentation set, which you should read sometime.
-      After installation, the documentation can be accessed by
-      pointing your browser to
-      <filename>/usr/local/pgsql/doc/html/index.html</filename>, unless you
-      changed the installation directories.
-     </para>
-
-     <para>
-      The first few chapters of the main documentation are the Tutorial,
-      which should be your first reading if you are completely new to
-      <acronym>SQL</acronym> databases.  If you are familiar with database
-      concepts then you want to proceed with part on server
-      administration, which contains information about how to set up
-      the database server, database users, and authentication.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Usually, you will want to modify your computer so that it will
-      automatically start the database server whenever it boots. Some
-      suggestions for this are in the documentation.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Run the regression tests against the installed server (using
-      <command>make installcheck</command>). If you didn't run the
-      tests before installation, you should definitely do it now. This
-      is also explained in the documentation.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      By default, <productname>PostgreSQL</productname> is configured to run on
-      minimal hardware.  This allows it to start up with almost any
-      hardware configuration. The default configuration is, however,
-      not designed for optimum performance. To achieve optimum
-      performance, several server parameters must be adjusted, the two
-      most common being <varname>shared_buffers</varname> and
-      <varname>work_mem</varname>.
-      Other parameters mentioned in the documentation also affect
-      performance.
-     </para>
-    </listitem>
-   </itemizedlist>
-  </para>
- </sect1>
-
- <xi:include href="postgres.sgml" xpointer="supported-platforms" xmlns:xi="http://www.w3.org/2001/XInclude"/>
- <xi:include href="postgres.sgml" xpointer="installation-platform-notes" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-</article>
diff --git a/doc/src/sgml/standalone-profile.xsl b/doc/src/sgml/standalone-profile.xsl
deleted file mode 100644
index ff464c1..0000000
--- a/doc/src/sgml/standalone-profile.xsl
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version='1.0'?>
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-                version="1.0">
-
-<!--
-This is a preprocessing layer to convert the installation instructions into a
-variant without links and references to the main documentation.
-
-- To omit something in the stand-alone INSTALL file, give the element a
-  condition="standalone-ignore" attribute.
-
-- If there is no element that exactly covers what you want to change, wrap it
-  in a <phrase> element, which otherwise does nothing.
-
-- Otherwise, write a custom rule below.
--->
-
-<xsl:output
-    doctype-public="-//OASIS//DTD DocBook XML V4.2//EN"
-    doctype-system="http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"/>
-
-<!-- copy everything by default -->
-
-<xsl:template match="@*|node()">
-  <xsl:copy>
-    <xsl:apply-templates select="@*|node()" />
-  </xsl:copy>
-</xsl:template>
-
-<!-- particular conversions -->
-
-<xsl:template match="*[@condition='standalone-ignore']">
-</xsl:template>
-
-<xsl:template match="phrase/text()['chapter']">
-  <xsl:text>document</xsl:text>
-</xsl:template>
-
-<xsl:template match="phrase[@id='install-ldap-links']">
-  <xsl:text>the documentation about client authentication and libpq</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='docguide-toolsets']">
-  <xsl:text>the main documentation's appendix on documentation</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='dynamic-trace']">
-  <xsl:text>the documentation</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='install-windows']">
-  <xsl:text>the documentation</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='pgcrypto']">
-  <xsl:text>pgcrypto</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='plpython-python23']">
-  <xsl:text>the </xsl:text><application>PL/Python</application><xsl:text> documentation</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='regress']">
-  <xsl:text>the file </xsl:text>
-  <filename>src/test/regress/README</filename>
-  <xsl:text> and the documentation</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='upgrading']">
-  <xsl:text>the documentation</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='uuid-ossp']">
-  <xsl:text>uuid-ossp</xsl:text>
-</xsl:template>
-
-<xsl:template match="xref[@linkend='xml2']">
-  <xsl:text>xml2</xsl:text>
-</xsl:template>
-
-</xsl:stylesheet>

---

From: Peter Eisentraut <[email-masked]>
Date: Tue, 28 Nov 2017 11:02:14 -0500

> 4. It doesn't generate complete postgres.sgml to process only the

What is the standalonetext attribute?  I don't see that in the DTD.
Wouldn't that fail validation?

Also, the makefile fragments need to be written differently.  You can't
use pipes; that would not catch any errors.

---

From: Alexander Lakhin <[email-masked]>
Date: Tue, 28 Nov 2017 19:55:11 +0300

Hello Peter,
> Wouldn't that fail validation?
I've added it to postgres.sgml as allowed by DocBook standard:
http://www.sagehill.net/docbookxsl/AddProfileAtt.html
+<!ENTITY % local.effectivity.attrib "standalonetext CDATA #IMPLIED">

> use pipes; that would not catch any errors.

I believe, that the last xsltproc will fail in case of error in previous 
command(s) as it will not get valid xml. For example, if sed failed with 
error, I get:
-:1: parser error : Document is empty

Best regards,
------
Alexander Lakhin