% $Id: tex4ht-xhtmml-xtpipes.tex 740 2020-06-13 22:35:32Z karl $
% htlatex tex4ht-xhtmml-xtpipes "xhtml,next,3" "" "-d./"

% Copyright 2009-2020 TeX Users Group
% Copyright 1996-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}
    \input{common.tex}
\begin{document}
\input tex4ht-cpright.tex
\input tex4ht-dir

%%%%%%%%%%%%%%%%%%
\part{Post Processing for HTML Output Mode}
%%%%%%%%%%%%%%%%%%


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

\AtEndDocument{\OutputCodE\<xhtmml.4xt\>}

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

\<xhtmml.4xt\><<<
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE xtpipes SYSTEM "xtpipes.dtd" >
<!-- xhtmml.4xt (`version), generated from `jobname.tex
     Copyright (C) 2009-2010 TeX Users Group
     Copyright (C) `CopyYear.2008. Eitan M. Gurari
`<TeX4ht copyright`> -->
<xtpipes preamble="yes" signature="xhtmml.4xt (`version)">
   <sax content-handler="xtpipes.util.ScriptsManager" 
        lexical-handler="xtpipes.util.ScriptsManagerLH" >
     `<p script`>
     `<li script`>
     `<table script`>
     `<mrow script`>
     `<math script`>
     `<mstyle script`>
   </sax>
</xtpipes>
>>>


% 
\AtEndDocument{\OutputCodE\<XhtmmlUtilities.java\>}

\ifdojava
  \Needs{"
  if [ ! -d \XTPIPES\space]; then exit 1; fi
  ;
  javac XhtmmlUtilities.java -d \XTPIPES
  "}
\fi

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

import org.w3c.dom.*;
public class XhtmmlUtilities {
  `<static void p(dom)`>
  `<static void li(dom)`>
  `<static void table(dom)`>
  `<static void mrow(dom)`>
  `<static void math(dom)`>
  `<void barsIntoFenced(dom)`>
  `<void digitsIntoNumbers(dom)`>
}
>>>





\<mrow script\><<<
<script element="mrow" >
   <dom name="." xml="." method="mrow" class="tex4ht.XhtmmlUtilities" />
</script> 
>>>




\<static void mrow(dom)\><<<
public static void mrow(Node dom) {
   barsIntoFenced( dom );
   digitsIntoNumbers( dom );
}
>>>


\<math script\><<<
<script element="math" >
   <dom name="." xml="." method="math" class="tex4ht.XhtmmlUtilities" />
   `<math-mstyle script`>
</script> 
>>>




\<static void math(dom)\><<<
public static void math(Node dom) {
   barsIntoFenced( dom );
   digitsIntoNumbers( dom );
}
>>>












%%%%%%%%%%%%%
\section{Empty Paragraphs}
%%%%%%%%%%%%%

\<p script\><<<
<script element="p" >
   <dom name="." xml="." method="p" class="tex4ht.XhtmmlUtilities" />
</script> 
>>>

\<p script\><<<
<script element="div" >
   <dom name="." xml="." method="p" class="tex4ht.XhtmmlUtilities" />
</script> 
>>>


\<static void p(dom)\><<<
public static void p(Node dom) {
   Node pNode = dom.getFirstChild();
   if( pNode.hasChildNodes() ){
      boolean drop = true;
      Node child = pNode.getFirstChild();
      while( child != null ){
         short type = child.getNodeType();
         if(              
             (type == Node.ELEMENT_NODE)
           ||             
             (type == Node.CDATA_SECTION_NODE)
           ||             
             (type == Node.TEXT_NODE)
           &&
             !((Text) child).getWholeText().trim().equals("")  
         ){         
            drop = false; break;
         }
         child = child.getNextSibling();
      }
      if( drop ){
         dom.removeChild( pNode );
      }        
   } else {
      dom.removeChild( pNode );
   }
}
>>>



%%%%%%%%%%%%%
\section{Tables}
%%%%%%%%%%%%%


Remove Empty Trailling Row

\<table script\><<<
<script element="table" >
   <dom name="." xml="." method="table" class="tex4ht.XhtmmlUtilities" />
</script> 
>>>


\<static void table(dom)\><<<
public static void table(Node dom) {
   Node tableNode = dom.getFirstChild();
   if( tableNode.hasChildNodes() ){
      Node trChild = tableNode.getLastChild();
      while( (trChild != null)
             &&
             !trChild.getNodeName().equals("tr") ){
         trChild = trChild.getPreviousSibling();
      }
      if( (trChild != null) && trChild.hasChildNodes() ){
         Node tdChild = trChild.getLastChild();
         while( (tdChild != null)
                &&
                !tdChild.getNodeName().equals("td") ){
            tdChild = tdChild.getPreviousSibling();
         }
         if( !tdChild.hasChildNodes() ){
            tableNode.removeChild( trChild );
         } else {
            Node child = tdChild.getFirstChild();
            if(
               (child.getNodeType() == Node.TEXT_NODE)
               &&
               ((Text) child).getWholeText().trim().equals("") 
               &&
               (child.getNextSibling() == null)
            ){
               tableNode.removeChild( trChild );
}  }  }  } }
>>>








%%%%%%%%%%%%%
\section{List Items}
%%%%%%%%%%%%%


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



\<li script\><<<
<script element="li" >
   <dom name="." xml="." method="li" class="tex4ht.XhtmmlUtilities" />
</script> 
>>>




\<static void li(dom)\><<<
public static void li(Node dom) {
   Node liNode = dom.getFirstChild();
   Node liChild;
   boolean hasBlock = false, hasInline = false;
   `<hasBlock, hasInline := exist in li?`>
   if( hasBlock && hasInline ){
      `<p := inline code`>
      `<insert p node as first child`>
   }
}
>>>




%%%%%%%%%%%%%
\subsection{Place Inline Code into Paragraphs}
%%%%%%%%%%%%%



\<p := inline code\><<<
liChild = liNode.getLastChild();
Element g = ((Document) dom).createElement("p");
g.setAttribute("class", "noindent");
while( liChild != null ){
   short type = liChild.getNodeType();
   if( `<liChild == block?`> ){
      `<insert p node after block node`>
      liChild = liChild.getPreviousSibling();
   } else {            
      Node nextChild = liChild;
      liChild = liChild.getPreviousSibling();
      `<move node into p`>
}  }
>>>


\<move node into p\><<<
nextChild = liNode.removeChild(nextChild);
type = nextChild.getNodeType();
if(
     (type != Node.COMMENT_NODE)
   &&
   (
     (type != Node.TEXT_NODE)
   ||
     !((Text) nextChild).getWholeText().trim().equals("") 
   )
){
   if( g.hasChildNodes() ){
      g.insertBefore( nextChild, g.getFirstChild() );
   } else {
      g.appendChild( nextChild );
} } 
>>>         

%%%%%%%%%%%%%
\subsection{Place Paragraphs into List Items}
%%%%%%%%%%%%%

\<insert p node as first child\><<<
if( liNode.hasChildNodes() ){
  liNode.insertBefore( g, liNode.getFirstChild() );
} else {
  liNode.appendChild( g );
}
>>>


\<insert p node after block node\><<<
if( g.hasChildNodes() ){
   Node nextChild = liChild.getNextSibling();
   if( nextChild == null  ){
      liNode.appendChild( g );
   } else {
      liNode.insertBefore( g, nextChild );
   }
   g = ((Document) dom).createElement("p");
   g.setAttribute("class", "noindent");
}
>>>



%%%%%%%%%%%%%
\subsection{Check Nature of Item Content}
%%%%%%%%%%%%%

\<hasBlock, hasInline := exist in li?\><<<
liChild = liNode.getFirstChild();
while( liChild != null ){
   short type = liChild.getNodeType();
   if( `<liChild == block?`> ){  hasBlock = true; }
   else if(  type == Node.TEXT_NODE ){ 
      if( !((Text) liChild).getWholeText().trim().equals("") ){
         hasInline = true;
   }  }
   else if( 
       (type != Node.COMMENT_NODE)
       &&
       (type != Node.PROCESSING_INSTRUCTION_NODE )
   ){ 
      hasInline = true;
   }
   liChild = liChild.getNextSibling();
}
>>>


\<liChild == block?\><<<
(type == Node.ELEMENT_NODE)
&&
(
   liChild.getNodeName().equals("p")
   ||
   liChild.getNodeName().equals("ol")
   ||
   liChild.getNodeName().equals("ul")
   ||
   liChild.getNodeName().equals("div")
   ||
   liChild.getNodeName().equals("table")
)
>>>



%%%%%%%%%%%%%%%%%%
\section{Scripted Math |...|}
%%%%%%%%%%%%%%%%%%





\<void barsIntoFenced(dom)\><<<
static void barsIntoFenced(Node dom) {
   Node rightBarNode = null;
   Node mrowNode = dom.getFirstChild();
   Node mrowChild = mrowNode.getLastChild();
   while( mrowChild != null ){
      if(
           mrowChild.getNodeName().equals("msub")
           ||
           mrowChild.getNodeName().equals("msup")
           ||
           mrowChild.getNodeName().equals("msubsup")
      ){
         Node firstChild = mrowChild.getFirstChild();
         if( 
             (firstChild.getChildNodes().getLength() == 1)
             &&
             firstChild.getTextContent().equals( "|" )
         ){
            rightBarNode = mrowChild;
      }  }
      else
      if(
         (rightBarNode != null)
         &&
         mrowChild.getNodeName().equals("mo")
         &&
         (mrowChild.getChildNodes().getLength() == 1)
         &&
         mrowChild.getTextContent().equals( "|" )
      ){
        if(mrowChild.getNextSibling() != rightBarNode){
            `<set mfenced sub,sup`>
        }
        rightBarNode = null;
      }
      mrowChild = mrowChild.getPreviousSibling();
}  }
>>>






\begin{verbatim}
               A + |B|^2 + C
<mrow> 
  <mi>A</mi> 
  <mo class="MathClass-bin">+</mo> 
  <mo class="MathClass-rel">|</mo>      #
  <mi>B</mi>                            #
  <msup>                                #
    <mrow>                              #
      <mo class="MathClass-rel">|</mo>  #
    </mrow>                             #
    <mrow>                              #
      <mn>2</mn>                        #
    </mrow>                             #
  </msup>                               #
  <mo class="MathClass-bin">+</mo> 
  <mi>C</mi> 
</mrow> 
\end{verbatim}


\<set mfenced sub,sup\><<<
rightBarNode.removeChild( rightBarNode.getFirstChild() );
Node sub = rightBarNode.getFirstChild();
Node mfenced = ((Document) dom).createElement( "mfenced" );
rightBarNode.insertBefore( mfenced, sub );
((Element) mfenced).setAttribute("open","|");
((Element) mfenced).setAttribute("close","|");
((Element) mfenced).setAttribute("separator","");
Node node = mrowChild.getNextSibling();
while( node != rightBarNode ){
   Node next = node.getNextSibling();
   mrowNode.removeChild( node );
   mfenced.appendChild( node );
   node = next;
}
mrowNode.removeChild( mrowChild );
mrowChild = mrowNode.getLastChild();
>>>


%%%%%%%%%%%%%%%%%%
\section{Digits into Numbers}
%%%%%%%%%%%%%%%%%%

\<void digitsIntoNumbers(dom)\><<<
static void digitsIntoNumbers(Node dom){
   Node mrowNode = dom.getFirstChild();
   Node mrowChild = mrowNode.getFirstChild();
   short state = `<init state`>;
   Node fromNode = null, 
          toNode = null;
   while( mrowChild != null ){
      switch( state ){
         case `<init state`>:
              if( mrowChild.getNodeName().equals("mn") ){
                 state = `<mn state`>;
                 fromNode = mrowChild;
                 toNode = mrowChild;
              }
            break;
         case `<mn state`>:
              boolean bool = true;
              if( mrowChild.getNodeName().equals("mn") ){
                 toNode = mrowChild;
                 bool = ( mrowChild.getNextSibling() == null );
              }  
              else
              { `<handle scripted numbers`> }
              if( bool )
              { `<bool := just single digits?`>
                if( bool ){
                   `<num := merge mn's`>
                   node.replaceChild( ((Document) dom).createTextNode(num),
                                      node.getFirstChild() 
                                    );
                }
                state = `<init state`>;
                fromNode = null;
                toNode = null;
      }       } 
      mrowChild = mrowChild.getNextSibling();
}  }
>>>


\<init state\><<<
0
>>>

\<mn state\><<<
1
>>>

\<num := merge mn's\><<<
Node next;
String num = "";
Node node = fromNode;
while( node != toNode ){
  num += node.getTextContent();
  next = node.getNextSibling();
  mrowNode.removeChild( node );
  node = next;
} 
num += node.getTextContent();
>>>

\<bool := just single digits?\><<<
for( Node node = fromNode; ; node = node.getNextSibling()){
  String str = node.getTextContent();
  if( str.length() > 1 ){ bool = false; break; }
  if( !str.replaceAll("[0-9]","").equals("") ){ bool = false; break; }    
  if( node == toNode ){ break; }
} 
>>>



\<handle scripted numbers\><<<
String s = null;
Node base;
if(
    ( mrowChild.getNodeName().equals("msub")
      ||
      mrowChild.getNodeName().equals("msup")
      ||
      mrowChild.getNodeName().equals("msubsup")
    )
    &&
    ((s = (base = mrowChild.getFirstChild())
          . getTextContent()).length() == 1 )
    &&
    s.replaceAll("[0-9]","").equals("")
){
   `<bool := just single digits?`>
   `<num := merge mn's`>
   mrowNode.removeChild( node );
   num += s;
   Node mn = ((Document) dom).createElement("mn");
   mn.appendChild( ((Document) dom).createTextNode(num) );
   mrowChild.replaceChild( mn, base);

   bool = false;
   state = `<init state`>;
   fromNode = null;
   toNode = null;
}
>>>



%%%%%%%%%%%%%%%%%%
\section{mstyle}
%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%
\subsection{Mstyle as Parent of an Element}
%%%%%%%%%%%%%

Merge mstyle into its child.  For instance

\begin{verbatim}
<mstyle mathvariant="bold">
   <mi>F</mi>
</mstyle>
\end{verbatim}

into

\begin{verbatim}
<mi mathvariant="bold">F</mi>
\end{verbatim}

\<mstyle script\><<<
<script element="mstyle" >
   <set name="mstyle" >
      `<open xslt script`>
      `<mstyle templates`>
      `<close xslt script`>
   </set>
   <xslt name="." xml="." xsl="mstyle" />
</script> 
>>>

\<mstyle templates\><<<
<xsl:template match=" m:mstyle [  
                  @mathvariant  
             and 
                  child::m:*[ not(@mathvariant) ] 
             and
                  (count(child::m:*) = 1)
] " > 
  <xsl:element name="{name(child::m:*[1])}"> 
    <xsl:attribute name="mathvariant" > 
         <xsl:value-of select="@mathvariant" /> 
    </xsl:attribute> 
    <xsl:apply-templates select="child::m:*/@*" /> 
    <xsl:apply-templates select=" 
        child::m:*/*  
        | child::m:*/text() 
        | child::m:*/comment() 
      "  
    /> 
  </xsl:element> 
</xsl:template> 
>>>

%%%%%%%%%%%%%
\subsection{Mstyle as Parent of Text}
%%%%%%%%%%%%%


\begin{verbatim}
<mi> 
  <mstyle mathvariant="bold">div</mstyle> 
</mi> 
\end{verbatim}

into

\begin{verbatim}
<mi mathvariant="bold">div</mi>
\end{verbatim}

\<math-mstyle script\><<<
<set name="math-mstyle" >
   `<open xslt script`>
   `<math-mstyle templates`>
   `<close xslt script`>
</set>
<xslt name="." xml="." xsl="math-mstyle" />
>>>


\<math-mstyle templates\><<<
<xsl:template match=" m:* [  
      not(self::m:math)
    and
      child::m:mstyle[ 
           @mathvariant
         and
           child::text()
         and
           (count(child::m:*) = 0)    
      ] 
    and
      (count(child::m:*) = 1)    
    and
      not(@mathvariant) 
] " > 
  <xsl:copy>
     <xsl:apply-templates select="@*" /> 
     <xsl:apply-templates select="m:mstyle/@*" /> 
     <xsl:apply-templates select="m:mstyle/text()" /> 
  </xsl:copy>
</xsl:template> 
>>>


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



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

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





%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% END END END END END END END END END END END END END END END END 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

