Subject: Re: Moving documentation to XML

From: Alexander Lakhin <[email-masked]>
Date: Fri, 30 Oct 2015 16:40:53 +0300

Hello, Guillaume.

We have plans to use this for russian translation, too. We translate the 
docs by converting (with xml2po) the single xml to postgres-ru.po and 
after translating it we convert it back to xml (we get postres-ru.xml 
here).  (Until now we had to perform one more conversion 
(postgres-ru.xml -> set of sgml's).)
So now we can get russian html/* with:
python xml2po.py -l ru -k -p postgres-ru.po postgres.xml >postgres-ru.xml
xsltproc --stringparam pg.version '9.4.1'  stylesheet.xsl postgres-ru.xml

But I had some doubts about DSSSL and XSL differences. As I noted 
previously there was at least one visible difference. So I decided to 
customize XSL templates to make sure that html's are generated without a 
loss or corruption.
I thought that comparing two HTML sources will not work, as they are too 
different, but maybe we can compare text generated from html by lynx, 
for example.
So I use the following procedure to look for differences:
0. Get dsssl-generated html's
make html
1. Extract text content from html's:
  for f in html/*.html; do fn=`basename $f`; echo $fn; cat $f | perl 
-0pi -pe 's/<B\s*>Note:\s*<\/B\s*>/\<h3>Note<\/h3>/g' | perl -0pi -pe 
's/><BLOCKQUOTE\s*CLASS="NOTE"/><div/ig' >/tmp/$fn; lynx /tmp/$fn --dump 
 >html-text/$fn;
* Some differences are not significant so it's not reasonable to modify 
XSL templates to eliminate them. Difference in "Note" placement and 
spelling is one of them, so I just filter it out.
2. Rename html to html-o and html-text to html-o-text.
3. Generate html's with XSL (use modified templates):
rm -r html; xsltproc --stringparam pg.version '9.4.1' stylesheet.xsl 
postgres.xml
4. Extract text content from html's as above.
5. Make sure that two text html's are identical:
diff -s -u -b -I '^\s*_\+\s*$' html-o-text/xtypes.html html-text/xtypes.html
* Differences in whitespaces and length of "____" lines are not 
significant, too.

For now, I've managed to get the same xtypes.html (I tested my XSL 
customizations with it), but I think, we can eliminate other most 
outstanding (or maybe all) differences likewise.
I can describe XSL customizations in more details, if needed.

Best regards,
Alexander

P.S. I couldn't post the message as a reply due to error on the 
postgresql.org side.
(<[email-masked]>: host makus.postgresql.org[174.143.35.229] 
said:
     550 Message headers fail syntax check (in reply to end of DATA 
command))

28.10.2015 14:46, Guillaume Lelarge wrote:
>
> Le 26 oct. 2015 6:40 PM, "Alexander Lakhin" <[email-masked]> 
> a écrit :
> >
> ...
> > To make sure that result of the transformation is the same, I've 
> compared original .html's with .html's generated with modified templates.
> > Unfortunately xslt generates random id's, so it's needed to exclude 
> them before comparing. I do that with:
> > for f in */*.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
> >
> >
> > So if it's acceptable way to speed up generation of HTML (and maybe 
> some other formats), what other steps should we take to move away from 
> SGML?
> > If the performance is still not satisfying, please let me know, I'll 
> continue to optimize xslt.
> > Beside performance issues, I can see some difference in results of 
> 'make html' and 'make xslthtml'. For example, see 
> doc/src/sgml/html/spi.html (xslt-generated version doesn't contain the 
> lists of functions).
> >
>
> What you've done is awesome. I can't wait to test it on the french 
> translation.
>
> Nice work!
>

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..95ca042
--- /dev/null
+++ b/doc/src/sgml/stylesheet-xhtml-dsssl-like.xsl
@@ -0,0 +1,266 @@
+<?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">
+
+<!-- align 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'">
+    <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>&#160;</xsl:otherwise>
+                </xsl:choose>
+              </td>
+              <th width="60%" align="center">
+                <xsl:choose>
+                  <xsl:when test="count($up) &gt; 0                                   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>
+
+<!-- align 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>
+
+
+<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()='chapter' 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>
+
+</xsl:stylesheet>
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..07be4a7 100644
--- a/doc/src/sgml/stylesheet.xsl
+++ b/doc/src/sgml/stylesheet.xsl
@@ -6,6 +6,8 @@
 
 <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" />
+<xsl:include href="stylesheet-xhtml-dsssl-like.xsl" />

 <!-- Parameters -->
@@ -13,7 +15,7 @@
 <xsl:param name="use.id.as.filename" select="'1'"></xsl:param>
 <xsl:param name="make.valid.html" select="1"></xsl:param>
 <xsl:param name="generate.id.attributes" select="1"></xsl:param>
-<xsl:param name="generate.legalnotice.link" select="1"></xsl:param>
+<xsl:param name="generate.legalnotice.link" select="0"></xsl:param>
 <xsl:param name="link.mailto.url">[email-masked]</xsl:param>
 <xsl:param name="chunk.first.sections" select="1"/>
 <xsl:param name="chunk.quietly" select="1"></xsl:param>
@@ -21,6 +23,9 @@
 
 <xsl:param name="website.stylesheet" select="0"/>
 
+<xsl:param name="generate.section.toc.level" select="1"></xsl:param>
+<xsl:param name="xref.with.number.and.title" select="0"></xsl:param>
+
 <xsl:param name="html.stylesheet">
   <xsl:choose>
     <xsl:when test="$website.stylesheet = 0">stylesheet.css</xsl:when>

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

---

From: Stefan Kaltenbrunner <[email-masked]>
Date: Mon, 2 Nov 2015 21:15:46 +0100

On 10/30/2015 02:40 PM, Alexander Lakhin wrote:
>  for f in html/*.html; do fn=`basename $f`; echo $fn; cat $f | perl -0pi
> -pe 's/<B\s*>Note:\s*<\/B\s*>/\<h3>Note<\/h3>/g' | perl -0pi -pe

Sorry for not replying earlier but most of the sysadmin team is not
tracking pgsql-docs that closely for issues - afaiks there was a typo in
your mail - the "To" in your mail looked like this:

To: pgsql-docs@postgresql org <[email-masked]>
  References: <[email-masked]>
<[email-masked]>
 <[email-masked]>
 <CAECtzeWiOkS=[email-masked]>

notice that there is a space after "pgsql-docs@postgresql" instead of
what I suspect should be a "." causing the header syntax check in exim
to barf on the mail.

Stefan