% $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}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%