% $Id: tex4ht-oo-xtpipes.tex 740 2020-06-13 22:35:32Z karl $
% htlatex tex4ht-oo-xtpipes "xhtml,next,3" "" "-d./"
%
% Copyright 2009-2020 TeX Users Group
% Copyright 2001-2009 Eitan M. Gurari
% Released under LPPL 1.3c+.
% See tex4ht-cpright.tex for license text.

\documentclass{article}
    \Configure{ProTex}{log,<<<>>>,title,list,`,[[]]}
    \usepackage{url}
\begin{document}

\input{common}
\input{tex4ht-cpright}
\input{tex4ht-dir}


%%%%%%%%%%%%%%%%%%
\section{Outline}
%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%
\subsection{Math}
%%%%%%%%%%%%%


\AtEndDocument{\OutputCodE\<oo-math.4xt\>}

\Needs{"xmllint --valid --noout oo-math.4xt"} 





\<oo-math.4xt\><<<
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE xtpipes SYSTEM "xtpipes.dtd" >
<!-- oo-math.4xt (`version), generated from `jobname.tex
     Copyright (C) 2009-2013 TeX Users Group
     Copyright (C) `CopyYear.2006. Eitan M. Gurari
`<TeX4ht copyright`> -->
<xtpipes preamble="yes" signature="oo-math.4xt (`version)">
   <sax content-handler="xtpipes.util.ScriptsManager,tex4ht.OomFilter" 
        lexical-handler="xtpipes.util.ScriptsManagerLH" >
      <script element="math:mtable" >
         `<normalizing math tables`>
      </script> 
      <script element="math:math" >
         `<handle mo elements`>
         `<handle mrow elements`>
         `<handle mspace elements`>
      </script> 
   </sax>
</xtpipes>
>>>







\<handle mspace elements\><<<
<set name="math:mspace" >
   `<open mml xslt script`>
   `<math:mspace templates`>
   `<close xslt script`>
</set>
<xslt name="." xml="." xsl="math:mspace" />
>>>


\<math:mspace templates\><<<
<xsl:template match="math:mspace" >
  <math:mtext>  
     <xsl:text> </xsl:text>
  </math:mtext>
</xsl:template> 
>>>




%%%%%%%%%%%%%
\subsection{Text}
%%%%%%%%%%%%%







\AtEndDocument{\OutputCodE\<oo-text.4xt\>}

\Needs{"xmllint --valid --noout oo-text.4xt"} 





\<oo-text.4xt\><<<
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE xtpipes SYSTEM "xtpipes.dtd" >
<!-- oo-text.4xt (`version), generated from `jobname.tex
     Copyright (C) 2009-2013 TeX Users Group
     Copyright (C) `CopyYear.2006. Eitan M. Gurari
`<TeX4ht copyright`> -->
<xtpipes preamble="yes" signature="oo-text.4xt (`version)">
   <sax content-handler="xtpipes.util.ScriptsManager,tex4ht.OoFilter" 
        lexical-handler="xtpipes.util.ScriptsManagerLH" >
      <script element="text:bibliography-mark" >
         `<bib mark`>
      </script> 
      <script element="table:table" >
         `<normalizing text tables`>
      </script> 
      <script element="text:p" >
         `<clean paragraphs`>
      </script> 
      <script element="text:h" >
         `<spaces for headers`>
      </script> 
   </sax>
</xtpipes>
>>>


%%%%%%%%%%%%%
\subsubsection{Cross References}
%%%%%%%%%%%%%

This is not used anymore, the make4ht-t4htlinks DOM filter is used instead. The
following code may produce broken or empty links, so it is not really usable.

\<cross references\><<<
<set name="t4ht-link" >
   `<open oo xslt script`>
    `<handle t4htlink elements`>
   `<close xslt script`>
</set>
<xslt name="." xml="." xsl="t4ht-link" />
>>>

\<bib mark\><<<
<set name="bib-mark" >
   `<open oo xslt script`>
    `<handle bib mark elements`>
   `<close xslt script`>
</set>
<xslt name="." xml="." xsl="bib-mark" />
>>>



\<handle t4htlink elements\><<<
<xsl:template match="t4htlink[ @href = concat('#',@name) ]" >
  <xsl:apply-templates select="*|text()|comment()" />
  <text:reference-mark>
     <xsl:attribute name="text:name">
        <xsl:value-of select="@name"/>
     </xsl:attribute>
     <xsl:text> </xsl:text>
  </text:reference-mark>
</xsl:template> 
>>>

\<handle t4htlink elements\><<<
<xsl:template match="t4htlink[ not(@name) 
                           and
                               starts-with(@href, '#') 
]" >
  <xsl:apply-templates select="*|text()|comment()" />
   <text:span>
        <xsl:attribute name="text:style-name">
           <xsl:text>reference-ref</xsl:text>
        </xsl:attribute>
     <text:reference-ref>
        <xsl:attribute name="text:ref-name">
           <xsl:value-of select="substring( @href, 2 )"/>
        </xsl:attribute>
        <xsl:attribute name="text:reference-format">
           <xsl:text>text</xsl:text>
        </xsl:attribute>
        <xsl:text> </xsl:text>   
     </text:reference-ref>
   </text:span>
</xsl:template> 
>>>







\<handle t4htlink elements\><<<
<xsl:template match="t4htlink[ not(@name) 
                           and
                               not(starts-with(@href, '#')) 
]" >
  <text:a>
     <xsl:attribute name="xlink:type">
        <xsl:text>simple</xsl:text>
     </xsl:attribute>
     <xsl:attribute name="xlink:href">
        <xsl:value-of select="@href"/>
     </xsl:attribute>
     <xsl:apply-templates select="*|text()|comment()" />
  </text:a>
</xsl:template> 
>>>





\<handle bib mark elements\><<<
<xsl:template match="text:bibliography-mark" >
   <xsl:copy>
     <xsl:attribute name="text:identifier">
        <xsl:value-of select="normalize-space(.)" />    
     </xsl:attribute>         
     <xsl:apply-templates select="@*" />
   </xsl:copy>
   <text:span>
      <xsl:attribute name="text:style-name">
         <xsl:text>reference-ref</xsl:text>
      </xsl:attribute>
      <text:reference-ref> 
        <xsl:attribute name="text:ref-name">
              <xsl:value-of 
                 select="text:span/text:reference-ref/@text:ref-name"/> 
        </xsl:attribute> 
        <xsl:attribute name="text:reference-format">
              <xsl:text>text</xsl:text> 
        </xsl:attribute>         
        <xsl:text> </xsl:text>
      </text:reference-ref> 
   </text:span>
</xsl:template> 
>>>





\begin{itemize}
\item
External
\begin{verbatim}
<text:a xlink:type="simple" 
        xlink:href="http:....">...</text:a>
\end{verbatim}


\item internal
\url{http://www.linuxjournal.com/article/8112}


\begin{verbatim}
<text:reference-mark-start text:name="xx"/>
is 
<text:reference-mark-end text:name="xx"/>

<text:reference-ref text:reference-format="direction" text:ref-name="xx">
above
</text:reference-ref> 
\end{verbatim}

\end{itemize}


%%%%%%%%%%%%%
\subsection{Java Utilities}
%%%%%%%%%%%%%



\AtEndDocument{\OutputCodE\<OoUtilities.java\>}

\ifdojava
  \Needs{"
    javac OoUtilities.java -d \XTPIPES
"}
\fi

\<OoUtilities.java\><<<
package tex4ht;
/* OoUtilities.java (`version), generated from `jobname.tex
   Copyright (C) 2009-2013 TeX Users Group
   Copyright (C) `CopyYear.2006. Eitan M. Gurari
`<TeX4ht copyright`> */
import org.w3c.dom.*;
public class OoUtilities {
  `<static void mtable(dom)`>
  `<static void table(dom)`>
  `<static boolean justSpace(node)`>
}
>>>


  `<static boolean paragraph(node)`>


%%%%%%%%%%%%%%%%%%
\section{Text Table}
%%%%%%%%%%%%%%%%%%

% 
% 
% 
% \<handle mrow elements\><<<
% <set name="math:mtd" >
%    `<open oo xslt script`>
%    `<math:mtd templates`>
%    `<close xslt script`>
% </set>
% <xslt name="." xml="." xsl="math:mtd" />
% >>>
% 
% \<math:mtd templates\><<<
% <xsl:template match="math:mtd" >
%   <xsl:copy>
%       <xsl:apply-templates select="*|text()" />
%   </xsl:copy>
% </xsl:template> 
% >>>
% 
% 
% \<math:mtd templates\><<<
% <xsl:template match="math:mtable">
%   <math:mtable math:columnalign="right left">
%       <xsl:apply-templates select="*|text()" />
%   </math:mtable>
% </xsl:template> 
% >>>
% 
% 
% 

 %%%%%%%%%%%%%
\subsection{Outline}
%%%%%%%%%%%%%





\<normalizing text tables\><<<
<dom name="." xml="." method="table" class="tex4ht.OoUtilities" />
>>>


\<static void table(dom)\><<<
public static void table(Node dom) {
      Node tblRow, tblCell, d;
//      int cols = 0;
   Node node = dom.getFirstChild();
   `<bind text namespace prefixes in the root element`>
   `<tblRow -= empty trailing rows`>
   if( (tblRow != null) && (tblRow.getPreviousSibling() != null) ){
     `<bool = is ruler row?`>
     if( !bool ){
        `<remove child spaces from row`>
        `<remove trailing non-content row`>
        tblCell = tblRow.getFirstChild();            
        if( (tblCell != null)
            && (tblCell.getNextSibling() == null)
            && justSpace(tblCell)
        ){
          node.removeChild(tblRow); 
   } }  } 
   `<n := max number of cols`>
   `<remove extra col declarations`>
}
>>>



\begin{verbatim}
<table:table >
  <table:table-column table:style-name="equ-col"/> 
  <table:table-column table:style-name="equ-num-col"/> 

  <table:table-row> 
    <table:table-cell table:style-name="equ-cell"> 
       ....
    </table:table-cell> 
  </table:table-row> 

  <table:table-row> 
       ....
  </table:table-row> 

</table:table> 
\end{verbatim}


%%%%%%%%%%%%%
\subsection{Remove Rows}
%%%%%%%%%%%%%





\<tblRow -= empty trailing rows\><<<
tblRow = node.getLastChild();
while( (tblRow != null) 
//       && (tblRow.getNodeType() == Node.TEXT_NODE)
//       && tblRow.getNodeValue().trim().equals("")             
       && tblRow.getTextContent().trim().equals("")             
){
   node.removeChild(tblRow); 
   tblRow = node.getLastChild();
}
>>>




%%%%%%%%%%%%%
\subsection{Remove Extra Column Declarations}
%%%%%%%%%%%%%



\<remove child spaces from row\><<<
tblCell = tblRow.getFirstChild();    
while( tblCell != null){
  d = tblCell.getNextSibling();                
  if( justSpace(tblCell) ){  tblRow.removeChild(tblCell);  }
  tblCell = d;
}
>>>




\<n := max number of cols\><<<
int n = 0;
tblRow = node.getFirstChild();
while( tblRow != null ){
   if( 
       (tblRow.getNodeType() == Node.ELEMENT_NODE)
     &&
        tblRow.getNodeName().equals("table:table-row")             
   ){
      `<m := number of columns`>
      if( m > n ){ n = m; }
   }
   tblRow = tblRow.getNextSibling();
}  
>>>

\<m := number of columns\><<<
int m = 0;
tblCell = tblRow.getFirstChild();
while( tblCell != null ){
   if( 
       (tblCell.getNodeType() == Node.ELEMENT_NODE)
     &&
        tblCell.getNodeName().equals("table:table-cell")             
   ){
      m++;
      `<table:table-cell -= empty text:p`>
   }
   tblCell = tblCell.getNextSibling();
}  
>>>





\<remove extra col declarations\><<<
tblRow = node.getFirstChild();
while( tblRow != null ){
   d = tblRow.getNextSibling();
   if( 
       (tblRow.getNodeType() == Node.ELEMENT_NODE)
     &&
        tblRow.getNodeName().equals("table:table-column")             
   ){
      n--;
      if( n < 0 ){
        tblRow.getParentNode().removeChild(tblRow);
  }  }  
  tblRow = d;
}
>>>


%%%%%%%%%%%%%
\subsection{Remove Empty Paragraphs within Table Cell}
%%%%%%%%%%%%%


There is an exception for paragraphs that are the only child elements.


\<table:table-cell -= empty text:p\><<<
Node child = tblCell.getLastChild();
while( child != null ){
   Node prevChild = child.getPreviousSibling();
   if( 
       (child.getNodeType() == Node.ELEMENT_NODE)
     &&
        child.getNodeName().equals("text:p")             
   ){
     Node sibling = child.getPreviousSibling();
     while( (sibling != null)
            &&
            (sibling.getNodeType() != Node.ELEMENT_NODE)
     ){
       sibling = sibling.getPreviousSibling();
     }
     if( sibling == null ){
       sibling = child.getNextSibling();
       while( (sibling != null)
              &&
              (sibling.getNodeType() != Node.ELEMENT_NODE)
       ){
          sibling = sibling.getNextSibling();
     } }        
     if( (sibling != null)
         && child.getTextContent().trim().equals("")             
     ){
         tblCell.removeChild(child); 
   } }
   child = prevChild;
}  
>>>



%%%%%%%%%%%%%
\subsection{Test for Empty Nodes}
%%%%%%%%%%%%%




\<static boolean justSpace(node)\><<<
static boolean justSpace(Node node){
   if( node == null ){ return true; }
   if( node.getNodeType() == Node.TEXT_NODE ){
       if( !node.getNodeValue().trim().equals("") ){ return false; }
   } else {
       if( node.getNodeType() == Node.ELEMENT_NODE ){
          String nm = node.getNodeName();
          if( 
                !nm.equals("table:table-cell")
             && !nm.equals("text:p")
          ){
             return false;
       }  }
   }
   if(!justSpace( node.getNextSibling() )){ return false; }
   if(!justSpace( node.getFirstChild() )){ return false; }
   return true;
}
>>>

\<bool = is ruler row?\><<<
boolean bool = false;
if( tblRow.getNodeName().equals("table:table-row")
    && tblRow.hasAttributes()      
){
   NamedNodeMap attributes = tblRow.getAttributes();
   Node styleAttr = attributes.getNamedItem( "table:style-name" );
   String style = (styleAttr==null)? null
                                   : styleAttr.getNodeValue();
   if( (style != null) 
       && (   style.equals("hline-row")
           || style.equals("cline-row")
          )
   ){
     bool = true;
}  }
>>>

%%%%%%%%%%%%%%%%%%
\section{Nested Paragraphs (OoUtilities)}
%%%%%%%%%%%%%%%%%%




\<clean paragraphs\><<<
<set name="text-p" >
   `<open oo xslt script`>
   `<remove nested text:p`>
   `<remove nested text:p in biblatex`>
   `<multicolumn styles`>
   `<close xslt script`>
</set>
<xslt name="." xml="." xsl="text-p" />
>>>




\<remove nested text:p2???\><<<
<xsl:template match="text:p[ @text:style-name = 'start_subjclass'
                           ]" >
   <xsl:comment>
       <xsl:text>start-subjclass</xsl:text>
   </xsl:comment>
   <xsl:apply-templates select="*|text()|comment()" />
</xsl:template> 
<xsl:template match="text:p[ @text:style-name = 'end_subjclass'>
   <xsl:apply-templates select="*|text()|comment()" />
   <xsl:comment>
       <xsl:text>end-subjclass</xsl:text>
   </xsl:comment>
</xsl:template> 
>>>



\<remove nested text:p\><<<
<xsl:template match="text:p[ (count(child::*)=1)  
                             and child::draw:frame
                             and parent::text:p
                           ]" >
    <xsl:apply-templates select="child::draw:frame" />
</xsl:template> 
>>>



\<remove nested text:p\><<<
<xsl:template match="text:p[
     child::text:p
   and
     (count(child::text:p) = count(child::*))
 ]" >
   <!--xsl:copy>
      <xsl:attribute name="text:style-name">
          <xsl:text>start_</xsl:text>
         <xsl:value-of select="@text:style-name" />
      </xsl:attribute-->      
      <xsl:comment>
          <xsl:text>start </xsl:text>
          <xsl:value-of select=" @text:style-name " />
     </xsl:comment>
   <!--/xsl:copy-->
       <xsl:apply-templates select="*|text()|comment()" mode="nested-p" />
   <!--xsl:copy>
      <xsl:attribute name="text:style-name">
          <xsl:text>end</xsl:text>
         <xsl:value-of select="@text:style-name" />
      </xsl:attribute-->      
      <xsl:comment>
          <xsl:text>end_</xsl:text>
          <xsl:value-of select=" @text:style-name " />
     </xsl:comment>
   <!--/xsl:copy-->
</xsl:template> 
>>>

\<remove nested text:p\><<<
<xsl:template match="*[not(text:p)]|text()|comment()" mode="nested-p" >
  <xsl:copy/>
</xsl:template> 
>>>

\<remove nested text:p\><<<
<xsl:template match="text:p" mode="nested-p" >
  <xsl:copy>
      <xsl:attribute name="text:style-name">
         <xsl:value-of select="parent::text:p/@text:style-name" />
         <xsl:text>_</xsl:text>
         <xsl:value-of select="@text:style-name" />
         <xsl:text>_</xsl:text>
         <xsl:value-of select="child::*[1]/@text:style-name" />
      </xsl:attribute>      
      <xsl:apply-templates select="@*[ name() != 'text:style-name' ]" />
      <xsl:apply-templates select="*|text()|comment()" />
  </xsl:copy>
</xsl:template> 
>>>

\<remove nested text:p in biblatex\><<<
<xsl:template
    match="text:p[
              parent::text:p/@text:style-name='printthebibliography-dd'
          ]" 
    mode="nested-p" >
  <xsl:copy>
      <xsl:attribute name="text:style-name">
         <xsl:value-of select="'printthebibliography-dd'" />
      </xsl:attribute>      
      <xsl:apply-templates select="@*[ name() != 'text:style-name' ]" />
      <xsl:apply-templates select="*|text()|comment()" />
  </xsl:copy>
</xsl:template> 
>>>












\<multicolumn styles\><<<
<xsl:template match="text:p[  child::text:span[ 
                       starts-with(@text:style-name, 'multicolumn-') 
                     ] ]" >
   <xsl:copy>
       <xsl:apply-templates 
            select="child::text:span[ 
                       starts-with(@text:style-name, 'multicolumn-') ]
                    /@*
                   " />
       <xsl:apply-templates select="*|text()|comment()" />
   </xsl:copy>
</xsl:template> 
<xsl:template match="text:span[ 
                       starts-with(@text:style-name, 'multicolumn-') ]" />
>>>


\<handle mixed content\><<<
System.out.println("handle mixed content " + name);
      int i=0;
      for( Node nd = first; nd != null; nd = nd.getNextSibling() ){ 
        nodeType = nd.getNodeType();
        `<trace mixed content`>
        i++;
      }
System.out.println("end handle mixed content " + name);
>>>

\<text:p into text:section\><<<
System.out.println("text:p into text:section");
>>>




\<trace mixed content\><<<
System.out.println(
i + "     "+  ((Boolean)v.get(i))
+

((nodeType == Node.TEXT_NODE)? 
    ("  TEXT: " + nd.getNodeValue() )
   : 
(
(nodeType == Node.ELEMENT_NODE)? 
     ("  " + nd.getNodeName())
     :
     ""
)
));
>>>>







%%%%%%%%%%%%%%%%%%
\section{Spaces for Headers}
%%%%%%%%%%%%%%%%%%

\<spaces for headers\><<<
<set name="headers" >
   `<open oo xslt script`>
   `<algorithmic templates`>
   `<biblatex bib templates`>
   `<close xslt script`>
</set>
<xslt name="." xml="." xsl="headers" />
>>>

\<algorithmic templates\><<<
<xsl:template match="text:h[@text:style-name='algorithmic-dt']" >
  <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="*|text()|comment()" mode="algorithmic"/>
  </xsl:copy>
</xsl:template> 
>>>


\<algorithmic templates\><<<
<xsl:template match="*|@*|comment()" mode="algorithmic" >
  <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="*|text()|comment()" mode="algorithmic"/>
  </xsl:copy>
</xsl:template> 
>>>



\<algorithmic templates\><<<
<xsl:template match="text()" mode="algorithmic" >
   <xsl:value-of select="translate(.,' ','&#xA0;')"/>
</xsl:template> 
>>>


\<biblatex bib templates\><<<
<xsl:template match="text:h[
     (@text:style-name='printthebibliography-dt')
     and
     (normalize-space()='')
]" >
</xsl:template> 
>>>


%%%%%%%%%%%%%%%%%%
\section{mo}
%%%%%%%%%%%%%%%%%%

\<handle mo elements\><<<
<set name="math:mo" >
   `<open mml xslt script`>
   <xsl:template match=" math:mo" >
   <xsl:choose>
     `<xsl:when mo...`>
     `<xsl:when mo length ...`>
     <xsl:otherwise>
        <math:mo>
           <xsl:apply-templates select="@*" />
           <xsl:value-of select="normalize-space(.)" />
        </math:mo>
     </xsl:otherwise>
   </xsl:choose>
   </xsl:template> 
   `<close xslt script`>
</set>
<xslt name="." xml="." xsl="math:mo" />
>>>





A translation of

\begin{verbatim}
          <math:mrow> 
            <math:mn>2</math:mn> 
            <math:mo>+</math:mo> 
          </math:mrow> 
\end{verbatim}

to

\begin{verbatim}
          <math:mrow> 
            <math:mn>2</math:mn> 
            <math:mo form="postfix">+</math:mo> 
          </math:mrow> 
\end{verbatim}

fails to satisfy OO. So the following alternative is offered

\begin{verbatim}
          <math:mrow> 
            <math:mn>2</math:mn> 
            <math:mtext>+</math:mtext> 
          </math:mrow> 
\end{verbatim}


\<xsl:when mo...\><<<
<xsl:when test=" 
   (preceding-sibling::math:mn or preceding-sibling::math:mi)
   and not(following-sibling::*)
" >
   <math:mtext>
      <xsl:apply-templates select="*|@*|text()" />
   </math:mtext>
</xsl:when> 
>>>




Isolated mo elements are problematic (e.g., 
\verb'<mtd><mo form="...">=</mo></mtd>') in OpenOffice
(\url{http://lists.w3.org/Archives/Public/www-math/2006Jul/0012.html})
so they are converted into mtext elements.




\<xsl:when mo...\><<<
<xsl:when test=" 
   not((preceding-sibling::*) or following-sibling::*)
" >
   <math:mtext>
      <xsl:apply-templates select="*|@*|text()" />
   </math:mtext>
</xsl:when> 
>>>

The original condition 
   `not(preceding-sibling::* or following-sibling::*)'
failed with java 1.6 at a MS OS. 


\begin{verbatim}
<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xlink="http://www.w3.org/1999/xlink"
   >
      <xsl:output omit-xml-declaration = "yes" />
<xsl:template match="mo" >
   <xsl:choose>
      <xsl:when test="preceding-sibling::* or following-sibling::*" >
      </xsl:when>
    </xsl:choose>
</xsl:template>
</xsl:stylesheet>


import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class Test {
   public static void main(String[] args)
        throws TransformerConfigurationException,
              TransformerException  {
    try{
       StreamSource xslt = new StreamSource(new File("test.xslt"));
       TransformerFactory fc = TransformerFactory.newInstance();
       Transformer transformer = fc.newTransformer( xslt );
    } catch (javax.xml.transform.TransformerConfigurationException e){
       
    } catch (Exception e){
       System.err.println(e);
} } }
\end{verbatim}




Failes on braces within mo elements \verb+<math:mo>{</math:mo>+.
Accepts them within mtext elements.


\<xsl:when mo...\><<<
<xsl:when test=" 
   (.='{') or (.='}')
" >
   <math:mtext>
      <xsl:apply-templates select="*|@*|text()" />
   </math:mtext>
</xsl:when> 
>>>



\begin{verbatim}
A \begin{eqnarray}a&=&b\end{eqnarray} is translated by tex4ht into 
 
    <mi>a</mi><mo>=</mo><mi>b</mi> 
 
and is loaded as 
 
     matrix {a # = # b} 
 
by OO2 into a broken display.  The xtpipe phase `fixes' the problem by 
producing improper mathml output 
 
    <mi>a</mi><mtext>=</mtext><mi>b</mi> 
 
which OO2 loads as 
 
    matrix {a # "=" # b} 
 
and provides proper display.  
\end{verbatim}





\<xsl:when mo...\><<<
<xsl:when test="  . = '='" >
  <xsl:choose>
     <xsl:when test="   not(preceding-sibling::*)
                     or not(following-sibling::*)
                     or preceding-sibling::*[1] / self::math:mo
     ">
        <math:mtext>
           <xsl:apply-templates select="*|@*|text()" />
        </math:mtext>
     </xsl:when>
     <xsl:otherwise>
        <math:mo>
           <xsl:apply-templates select="*|@*|text()" />
        </math:mo>
     </xsl:otherwise>
  </xsl:choose>

</xsl:when> 
>>>




In cases like \verb!$m \bmod  n$!, OpenOffice swallos the characters following the first one.

\<xsl:when mo length ...\><<<
<xsl:when test=" string-length() &gt; 1 " >
   <math:mtext>
      <xsl:value-of select="normalize-space(.)" />
   </math:mtext>
</xsl:when> 
>>>


%%%%%%%%%%%%%%%%%%
\section{mrow}
%%%%%%%%%%%%%%%%%%



OpenOffice 2 loads

\begin{verbatim}
<math:msub> 
    <math:mrow> 
      <math:mi>x</math:mi> 
    </math:mrow> 
    <math:mrow> 
      <math:msub> 
        <math:mrow> 
          <math:mi>i</math:mi> 
        </math:mrow> 
        <math:mrow> 
          <math:mi>j</math:mi> 
        </math:mrow> 
      </math:msub> 
    </math:mrow> 
  </math:msub> 
\end{verbatim}

and 
 
\begin{verbatim}
    <math:msub>  
      <math:mi>x</math:mi>  
      <math:msub>  
        <math:mi>i</math:mi>  
        <math:mi>j</math:mi>  
      </math:msub>  
    </math:msub>  
\end{verbatim}

into \verb'x_i_j' which is a broken expression. Editing in OpenOffice the source
into 
\verb'x_{i_j}'
or
\verb'{x}_{{i}_{j}}'








\<handle mrow elements NO\><<<
<set name="math:mrow" >
   `<open mml xslt script`>
   `<math:mrow templates`>
   `<close xslt script`>
</set>
<xslt name="." xml="." xsl="math:mrow" />
>>>





\<math:mrow templates\><<<
<xsl:template match=" math:mrow[ count(child::*)=1 ]" >
      <xsl:apply-templates select="*|@*|text()" />  
</xsl:template> 
>>>


\begin{verbatim}
The output of tex4ht on $x_{i_j}$ is  
 
   <math:msub> 
       <math:mrow> 
         <math:mi>x</math:mi> 
       </math:mrow> 
       <math:mrow> 
         <math:msub> 
           <math:mrow> 
             <math:mi>i</math:mi> 
           </math:mrow> 
           <math:mrow> 
             <math:mi>j</math:mi> 
           </math:mrow> 
         </math:msub> 
       </math:mrow> 
     </math:msub> 
    
and OO2 loads the code into a broken format and view x_i_j.  The same 
outcome occurs when tex4ht is modified to produce the following output. 
        
       <math:msub> 
         <math:mi>x</math:mi> 
         <math:msub> 
           <math:mi>i</math:mi> 
           <math:mi>j</math:mi> 
         </math:msub> 
       </math:msub> 
 
A manual editing of x_i_j into {x}_{{i}_{j}} or x_{i_j} provides the 
proper display (and identical mathml code). 
\end{verbatim}


%%%%%%%%%%%%%%%%%%
\section{Dimenstions of Math Tables}
%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%
\subsection{Background}
%%%%%%%%%%%%%





All columns explicitly require identical number of columns.

Broken: 

\begin{verbatim}
<math:mtable > 
  <math:mtr> 
    <math:mtd columnalign="left"><math:mn>1</math:mn></math:mtd> 
    <math:mtd columnalign="left"><math:mn>2</math:mn></math:mtd> 
  </math:mtr> 
  <math:mtr> 
    <math:mtd columnalign="left"><math:mn>1</math:mn></math:mtd> 
  </math:mtr> 
</math:mtable> 
\end{verbatim}

Works:

\begin{verbatim}
<math:mtable > 
  <math:mtr> 
    <math:mtd columnalign="left"><math:mn>1</math:mn></math:mtd> 
    <math:mtd columnalign="left"><math:mn>2</math:mn></math:mtd> 
  </math:mtr> 
  <math:mtr> 
    <math:mtd columnalign="left"><math:mn>1</math:mn></math:mtd> 
    <math:mtd columnalign="left"></math:mtd> 
  </math:mtr> 
</math:mtable> 
\end{verbatim}


The last \verb+\\+ produces extra line with single entry and no data.

\begin{verbatim}
$ 
\begin{cases}  
    1 & 2\\ 
    3 & 4\\ 
\end{cases} 
$ 
\end{verbatim}

Singlton mspace breaks math tables:

\begin{verbatim}
<math:mtable> 
  <math:mtr> 
      <math:mtd><math:mn>1</math:mn></math:mtd> 
      <math:mtd><math:mspace width="1em"/></math:mtd> 
  </math:mtr> 
</math:mtable> 
\end{verbatim}

%%%%%%%%%%%%%
\subsection{Outline}
%%%%%%%%%%%%%

\<normalizing math tables\><<<
<dom name="." xml="." method="mtable" class="tex4ht.OoUtilities" />
>>>


\<static void mtable(dom)\><<<
public static void mtable(Node dom) {
      Node mtr, mtd, d;
      int cols = 0;
  Node node = dom.getFirstChild();
   `<remove trailing non-content entries`>
   `<fill rows`>
}
>>>


 




%%%%%%%%%%%%%
\subsection{Remove Trailing Entries}
%%%%%%%%%%%%%

\<remove trailing non-content entries\><<<
if (node.hasChildNodes()) {
   mtr = node.getLastChild();
   while( mtr != null){
      if( mtr.getNodeType() == Node.ELEMENT_NODE ){
         if (mtr.hasChildNodes()) {
           mtd = mtr.getLastChild();            
           int count = 0;
           while( mtd != null){
             if( mtd.getNodeType() == Node.ELEMENT_NODE ){
                count++;
                d = mtd.getFirstChild();                
                if( d != null ){  
                   `<remove mspace-only content`>
                }
                if( d != null ){  
                   `<remove d, if white space text`>         
             }  }
             d = mtd;
             mtd = mtd.getPreviousSibling();
             `<remove d, if white space text`>
             if( (d != null) 
                  && (d.getNodeType() == Node.ELEMENT_NODE) ){
               `<remove d, if trailing and childless node`>
               if( d == null ){ count--; }
           } } 
           if( count > cols ){ cols = count; }
      } }  
      d = mtr;
      mtr = mtr.getPreviousSibling();
      `<remove d, if white space text`>         
      if( d != null ){
         `<remove d, if trailing and childless node`>
}  }  }
>>>


\<remove d, if white space text\><<<
if( 
    (d.getNodeType() == Node.TEXT_NODE)
    && d.getNodeValue().trim().equals("")
){
    d.getParentNode().removeChild(d); 
    d = null;
}
>>>

\<remove d, if trailing and childless node\><<<
if( (d.getNextSibling()==null) 
    && (d.getFirstChild()==null)  ){
   d.getParentNode().removeChild(d); 
   d = null;
}
>>>





%%%%%%%%%%%%%
\subsection{Fill Rows}
%%%%%%%%%%%%%





\<fill rows\><<<
if (node.hasChildNodes()) {
   mtr = node.getFirstChild();
   while( mtr != null){
      if( mtr.getNodeType() == Node.ELEMENT_NODE ){
         int count = 0;
         if (mtr.hasChildNodes()) {
           mtd = mtr.getFirstChild(); 
           while( mtd != null){
             if( mtd.getNodeType() == Node.ELEMENT_NODE ){
                `<insert new line text node`>
                count++;
             }  
             mtd = mtd.getNextSibling();
           }
         } 
         if( count < cols ){ 
            `<fill with empty mtd nodes`>
      }  }
      mtr = mtr.getNextSibling();
}  }  
>>>

\<fill with empty mtd nodes\><<<
for(int i = count; i < cols; i++){
  mtr.appendChild( ((Document) dom).createElement("math:mtd") );
}
>>>

\<insert new line text node\><<<
mtr.insertBefore( ((Document) dom).createTextNode("\n"), mtd );
>>>


%%%%%%%%%%%%%
\subsection{mspace}
%%%%%%%%%%%%%


\<remove mspace-only content\><<<
boolean remove = true;
for(Node i=d; i!=null; i=i.getNextSibling() ){
   if( (i.getNodeType() == Node.ELEMENT_NODE)  
       && !i.getNodeName().equals("math:mspace") ) {
      remove = false; break;
}  }
if( remove ){
   while( d != null ){
     mtd.removeChild(d); 
     d = mtd.getFirstChild();
}  }
>>>

%%%%%%%%%%%%%%%%%%
\section{Shared}
%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%
\subsection{XSLT Setup}
%%%%%%%%%%%%%





\<open oo xslt script\><<<
<![CDATA[ 
   <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

      xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"   
      xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"   
      xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"   
      xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"   
      xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"   
      xmlns:fo="http://www.w3.org/1999/XSL/Format"   
      xmlns:xlink="http://www.w3.org/1999/xlink"   
      xmlns:dc="http://purl.org/dc/elements/1.1/"   
      xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"   
      xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"  
      xmlns:svg="http://www.w3.org/2000/svg"   
      xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"   
      xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"   
      xmlns:math="http://www.w3.org/1998/Math/MathML"   
      xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"   
      xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"   
      xmlns:ooo="http://openoffice.org/2004/office"   
      xmlns:ooow="http://openoffice.org/2004/writer"   
      xmlns:oooc="http://openoffice.org/2004/calc"   
      xmlns:dom="http://www.w3.org/2001/xml-events"   
      xmlns:xforms="http://www.w3.org/2002/xforms"   
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"   
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   >
      <xsl:output omit-xml-declaration = "yes" />
>>>



\<open mml xslt script\><<<
<![CDATA[ 
   <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:math="http://www.w3.org/1998/Math/MathML"   
      xmlns:xlink="http://www.w3.org/1999/xlink"   
   >
      <xsl:output omit-xml-declaration = "yes" />
>>>


\<close xslt script\><<<
      <xsl:template match="*|@*|text()|comment()" >
        <xsl:copy>
          <xsl:apply-templates select="*|@*|text()|comment()" />
        </xsl:copy>
      </xsl:template>
   </xsl:stylesheet> 
]]>
>>>




%%%%%%%%%%%%%
\subsection{Text Namespaces}
%%%%%%%%%%%%%


\<bind text namespace prefixes in the root elementNO\><<<
((Element) node).setAttribute(
      "xmlns:office",
      "urn:oasis:names:tc:opendocument:xmlns:office:1.0"   
);
((Element) node).setAttribute(
      "xmlns:style",
      "urn:oasis:names:tc:opendocument:xmlns:style:1.0"   
);
((Element) node).setAttribute(
      "xmlns:text",
      "urn:oasis:names:tc:opendocument:xmlns:text:1.0"   
);
((Element) node).setAttribute(
      "xmlns:table",
      "urn:oasis:names:tc:opendocument:xmlns:table:1.0"   
);
((Element) node).setAttribute(
      "xmlns:draw",
      "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"   
);
((Element) node).setAttribute(
      "xmlns:fo",
      "http://www.w3.org/1999/XSL/Format"   
);
((Element) node).setAttribute(
      "xmlns:xlink",
      "http://www.w3.org/1999/xlink"   
);
((Element) node).setAttribute(
      "xmlns:dc",
      "http://purl.org/dc/elements/1.1/"   
);
((Element) node).setAttribute(
      "xmlns:meta",
      "urn:oasis:names:tc:opendocument:xmlns:meta:1.0"   
);
((Element) node).setAttribute(
      "xmlns:number",
      "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"  
);
((Element) node).setAttribute(
      "xmlns:svg",
      "http://www.w3.org/2000/svg"   
);
((Element) node).setAttribute(
      "xmlns:chart",
      "urn:oasis:names:tc:opendocument:xmlns:chart:1.0"   
);
((Element) node).setAttribute(
      "xmlns:dr3d",
      "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"   
);
((Element) node).setAttribute(
      "xmlns:math",
      "http://www.w3.org/1998/Math/MathML"   
);
((Element) node).setAttribute(
      "xmlns:form",
      "urn:oasis:names:tc:opendocument:xmlns:form:1.0"   
);
((Element) node).setAttribute(
      "xmlns:script",
      "urn:oasis:names:tc:opendocument:xmlns:script:1.0"   
);
((Element) node).setAttribute(
      "xmlns:ooo",
      "http://openoffice.org/2004/office"   
);
((Element) node).setAttribute(
      "xmlns:ooow",
      "http://openoffice.org/2004/writer"   
);
((Element) node).setAttribute(
      "xmlns:oooc",
      "http://openoffice.org/2004/calc"   
);
((Element) node).setAttribute(
      "xmlns:dom",
      "http://www.w3.org/2001/xml-events"   
);
((Element) node).setAttribute(
      "xmlns:xforms",
      "http://www.w3.org/2002/xforms"   
);
((Element) node).setAttribute(
      "xmlns:xsd",
      "http://www.w3.org/2001/XMLSchema"   
);
((Element) node).setAttribute(
      "xmlns:xsi",
      "http://www.w3.org/2001/XMLSchema-instance"
);
>>>


%%%%%%%%%%%%%%%%%%
\section{Unicode in mtex}
%%%%%%%%%%%%%%%%%%

Openoffice dies on non-breaking space characters \verb+&#xA0;+ within
mtext.
 

\begin{verbatim}
\documentclass{amsart} 
\begin{document} 
  $\text{ the number of spanning trees of }$ 
\end{document} 
\end{verbatim}



\AtEndDocument{\OutputCodE\<OomFilter.java\>}

\ifdojava
  \Needs{"
    javac OomFilter.java     -d \XTPIPES
"}
\fi

\<OomFilter.java\><<<
package tex4ht;
/* OomFilter.java (`version), generated from `jobname.tex
   Copyright (C) 2009-2010 TeX Users Group
   Copyright (C) `CopyYear.2002. Eitan M. Gurari
`<TeX4ht copyright`> */

import org.xml.sax.helpers.*;
import org.xml.sax.*;
import java.io.PrintWriter;

public class OomFilter extends XMLFilterImpl {
     PrintWriter out = null;
     boolean mtext = false;
   public OomFilter( PrintWriter out, 
                     PrintWriter log, boolean trace ){
     this.out = out;
   }
   public void startElement(String ns, String sName,
                           String qName, Attributes attr) {
      if( qName.equals( "math:mtext" ) ){ mtext = true; }
      try{
           super.startElement(ns, sName, qName, attr);
      } catch( Exception e ){
        System.err.println( "--- OomFilter Error 1 --- " + e);
      }  
   }
   public void endElement(String ns, String sName, String qName){
      if( qName.equals( "math:mtext" ) ){ mtext = false; }
      try{
        super.endElement(ns, sName, qName);
      } catch( Exception e ){
        System.err.println( "--- OomFilter Error 2 --- " + e);
   }  }
   public void characters(char[] ch, int start, int length){
      try{
        if ( mtext ) {
           for(int i = start; i<start+length; i++){
              if( ch[i] == 160 ){ ch[i] = ' '; }
        }  }
        super.characters(ch, start, length);
      } catch( Exception e ){
        System.out.println( "--- OomFilter Error 3 --- " + e);
}  }  }
>>>




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{OoFilter}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%
\subsection{Outline}
%%%%%%%%%%%%%


\AtEndDocument{\OutputCodE\<OoFilter.java\>}

\ifdojava
  \Needs{"
    javac OoFilter.java      -d \XTPIPES
"}
\fi

\<OoFilter.java\><<<
package tex4ht;
/* OoFilter.java (`version), generated from `jobname.tex
   Copyright (C) 2009-2010 TeX Users Group
   Copyright (C) `CopyYear.2002. Eitan M. Gurari
`<TeX4ht copyright`> */
`<OoFilter imports`>
public class OoFilter extends XMLFilterImpl {
     PrintWriter out = null;
   public OoFilter( PrintWriter out, 
                    PrintWriter log, boolean trace ){
     this.out = out;
   }
   public void startElement(String ns, String sName,
                           String qName, Attributes attr) {
      if( qName.equals( "draw:frame" ) ){ 
        `<set dimensions of figures`>
      }
      try{
           super.startElement(ns, sName, qName, attr);
      } catch( Exception e ){
        System.err.println( "--- OoFilter Error 1 --- " + e);      
   }  }
   public void processingInstruction(String target, String fileName) {
      if( target.equals("tex4ht-lg") ){
         fileName = fileName.trim();
         if( fileName.replaceAll(" ","").startsWith("file=") ){
            `<load font vars`>
            `<load font styles`>
   }  }  }
}
>>>



%%%%%%%%%%%%%
\subsection{Dimensions for Figures}
%%%%%%%%%%%%%

\<set dimensions of figures\><<<
String name = attr.getValue("draw:name");
if( (name != null) 
    && (attr.getValue("svg:width") == null) 
    && (attr.getValue("svg:height") == null) 
){ 
  java.awt.Image image = new javax.swing.ImageIcon(name).getImage(); 
  int width = image.getWidth(null); 
  int height = image.getHeight(null); 
  if( (width>0) && (height>0) ){
     org.xml.sax.helpers.AttributesImpl attrs = 
                   new  org.xml.sax.helpers.AttributesImpl( attr );
     attrs.addAttribute(null, "svg:width", "svg:width",
                                 "String", (width * 72 / 110) + "pt");
     attrs.addAttribute(null, "svg:width", "svg:height",
                                 "String", (height * 72 / 110) + "pt");
     attr = attrs; 
} }
>>>


%%%%%%%%%%%%%
\subsection{Font Styles}
%%%%%%%%%%%%%




\<load font styles\><<<
int length = fileName.length();
int loc = fileName.indexOf(fileName.charAt(length-1));           
fileName = fileName.substring(loc+1,length-1);
try{ 
   String s = "";
   FileReader fr  = new FileReader( fileName ); 
   BufferedReader in = new BufferedReader( fr ); 
                      `<htfcss from lg`>
   `<rewind lg file`> `<font=(...) from lg`>
   `<rewind lg file`> `<Font-css-base: ...`>
   `<rewind lg file`> `<process Font-Size: ...`>
   `<rewind lg file`> `<process Font(...)`>
} catch(Exception e){ 
   System.err.println( "--- OoFilter Error 2 --- " + e);      
}  
>>>

\<rewind lg file\><<<
in.close();
fr  = new FileReader( fileName ); 
in = new BufferedReader( fr ); 
>>>








\<htfcss from lg\><<<
try{
   String key = "", body = "";
   while( (s=in.readLine()) != null ){ 
     if( s.startsWith("htfcss: ") ){
        s = s.substring(8);
        int idx = s.indexOf(' ');
        if( idx == 0 ){
           body += s;
        } else {
           `<map += (key, body)`>
           if( idx == -1 ){
              key = s; body = "";
           } else {
              key = s.substring(0,idx);
              body = s.substring(idx);
   } }  }  }
   `<map += (key, body)`>
} catch(java.lang.NumberFormatException e){ 
   System.err.println( "--- OoFilter Error 3 --- Improper record: " + s);
}
>>>




\<map += (key, body)\><<<
body = body.trim();
if( body.startsWith( "@media " ) ){   
   body = body.substring(7).trim();
   if( body.startsWith("print ") ){
     body = body.substring(6).trim();
   } else { key = ""; }
}
if( !key.equals("") ){
   String [] property = body.split(";");
   for( int i=0; i<property.length; i++ ){
      if( !property[i].trim().equals("") ){
         int indx = property[i].indexOf(":");
         if( indx != -1 ){
            String name = property[i].substring(0,indx).trim();
            String value = (property[i]+' ').substring(indx+1).trim();
            if( !name.equals("") && !value.equals("") ){
               `<map[key] += (name,value)`>
}  }  }  }  }
>>>


\<map[key] += (name,value)\><<<
if( map.containsKey(key) ){
   HashMap <String,String> entry = map.get(key);
   entry.put(name,value);
}
else
{
   HashMap <String,String> entry = new HashMap <String,String>();
   entry.put(name,value);
   map.put(key,entry);
}
>>>


\<load font vars\><<<
HashMap <String,HashMap <String,String>> map
       = new HashMap<String,HashMap <String,String>>();
>>>







\<Font-css-base: ...\><<<
try{
   while( (s=in.readLine()) != null ){ 
     if( s.startsWith("Font_css_base: ") ){
       int idx = s.indexOf("Font_css_mag: ");
       if( idx != -1 ){
          String [] pattern = s.substring(15,idx).trim().split("%s");
          if( pattern.length == 3 ){ font_css_base = pattern; }
          pattern = (s+' ').substring(idx).trim().split("%s");
          if( pattern.length == 2 ){ font_css_mag = pattern; }
   } } }
} catch(Exception e){ 
   System.err.println( "--- OoFilter Error 4 --- Improper record: " + s);
}
>>>




\<process Font-Size: ...\><<<
try{
   while( (s=in.readLine()) != null ){ 
     if( s.startsWith("Font_Size:") ){
        base_font_size = Integer.parseInt( s.substring(10).trim() ); 
   } } 
} catch(java.lang.NumberFormatException e){ 
   System.err.println( "--- OoFilter Error 5 --- Improper record: " + s);
}
>>>

\<process Font(...)\><<<
try{
   while( (s=in.readLine()) != null ){ 
     if( s.startsWith("Font(") ){
        String [] match = s.split("\"");
        match[1] = match[1].trim();
        match[2] = match[3].trim();
        match[3] = match[5].trim();
        match[4] = match[7].trim();
        `<get font size`>
        `<get font style`>
   } } 
} catch(Exception e){ 
   System.err.println( "--- OoFilter Error 6 --- Improper record: " + s);
}
>>>




\<get font style\><<<
HashMap <String,String> entry = map.get(match[1]);
if( (entry != null) || (second < 98) || (second > 102) ){
   String styleName = font_css_base[0] + match[1] +
                      font_css_base[1] + match[2] +
                      font_css_base[2];
   if( !match[4].equals("100") ){ 
      styleName += font_css_mag[0] + match[4] + font_css_mag[1]; 
   }
   `<attr[style:style] := ...`>
   super.startElement(null, "style:style", "style:style", attr);
   `<attr[style:text-properties] := ...`>
   super.startElement(null, "style:text-properties", 
                                 "style:text-properties", attr);
   super.endElement(null, "style:text-properties",
                                       "style:text-properties");
   super.endElement(null, "style:style", "style:style");
}
>>>


\<attr[style:style] := ...\><<<
org.xml.sax.helpers.AttributesImpl attr =
                      new org.xml.sax.helpers.AttributesImpl();
attr.addAttribute("", "style:name", "style:name", "String", styleName);
attr.addAttribute("", "style:family", "style:family", "String", "text");
>>>

\<attr[style:text-properties] := ...\><<<
attr = new org.xml.sax.helpers.AttributesImpl();
if( entry != null ){
   Object [] name = entry.keySet().toArray();
   for(int i=0; i < name.length; i++){
      String value = entry.get(name[i]);
      attr.addAttribute("", "fo:" + (String) name[i],
                            "fo:" + (String) name[i],
                                                "String", value);
}  }
if( (second < 98) || (second > 102) ){
   attr.addAttribute("", "fo:font-size", "fo:font-size", 
                                  "String", (second / 10.0) + "pt");
}
>>>

    
%                     style:font-family-generic=\"swiss\"  
%                     style:font-pitch=\"variable\"

\<load font vars\><<<
String [] font_css_base = {"" , "-", ""};
String [] font_css_mag = {"x-x-", ""};
>>>


\<print font style css\><<<
(IGNORED) fprintf(css_file, 
   (Font_css_base == NULL)? ".%s-%s" : Font_css_base,
   match[1], match[2]);
if( !eq_str(match[4],"100") ){ 
   (IGNORED) fprintf(css_file,
   (Font_css_mag == NULL)? "x-x-%s" : Font_css_mag,
   match[4]);
}
(IGNORED) fprintf(css_file, "{");
if( (second < 98) || (second > 102) ){
   (IGNORED) fprintf(css_file, "font-size:%d%c;", second, '%');
}
if( font_sty  ) {
   (IGNORED) fprintf(css_file, font_sty->body);
}
(IGNORED) fprintf(css_file, "}\n");
>>>





\<get font size\><<<
{  
   if( match[3].replaceAll("[0-9]","").equals("") ){
      second =   (int) 
              (  Integer.parseInt( match[3] )
               * Long.parseLong( match[4] )
               / base_font_size
              );
      while( second > 700 ){  second /= 10; }
   } else { second = 100; }
   `<inspect font-size argument`>
}
>>>

The following case handles cases like that of 
`\verb'Font("ecti","1095","10","100")'', where
\verb=base_font_size= is 11.

\<inspect font-size argument\><<<
if(  (int) (  Double.parseDouble(match[2])
            / Long.parseLong(match[4])
            + 0.5
           )
      == base_font_size
){
   second = 100;
};
>>>



\<load font vars\><<<
int base_font_size = 10;
int second;
>>>


\<OoFilter imports\><<<
import java.util.*;
import org.xml.sax.helpers.*;
import org.xml.sax.*;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.FileReader;
>>>


\ifdojava
\AtEndDocument{\Needs{%
    "pushd \XTPIPES || exit 1
     ;  
     jar cf tex4ht.jar *
     ;
     popd
     ;
     mv \XTPIPES tex4ht.jar \TEXMFTEXivBIN
     ;
     if [ ! -d \TEXMFTEXivXTPIPES\space]; then exit 1; fi
     ;
     cp \XTPIPES xtpipes/lib/* 
        \TEXMFTEXivXTPIPES
"}}
\fi

\end{document}
