| | import com.whitemagicsoftware.keenquotes.parser.Apostrophe; |
| | import org.w3c.dom.Document; |
| | +import org.w3c.dom.Node; |
| | +import org.w3c.dom.NodeList; |
| | |
| | import java.io.File; |
| | import java.io.FileNotFoundException; |
| | import java.nio.file.Path; |
| | import java.util.*; |
| | +import java.util.function.Consumer; |
| | |
| | import static com.keenwrite.Bootstrap.APP_TITLE_ABBR; |
 |
| | final var footText = mContext.getHtmlFoot(); |
| | |
| | - append( headText, doc, "/html/head" ); |
| | - append( footText, doc, "/html/body" ); |
| | + append( headText, doc ); |
| | + append( footText, doc ); |
| | |
| | final var map = mContext.getInterpolatedDefinitions(); |
 |
| | } |
| | |
| | - public void append( final String html, Document target, String path ) { |
| | + public void append( final String html, final Document target ) { |
| | + assert html != null; |
| | + assert target != null; |
| | + |
| | try { |
| | final var source = DocumentConverter.parse( html ); |
| | final var sourceBody = source.head(); |
| | final var sourceDoc = CONVERTER.fromJsoup( sourceBody ); |
| | + final var sourceRoot = sourceDoc.getDocumentElement(); |
| | + final var children = sourceRoot.getChildNodes(); |
| | |
| | - final var targetNode = DocumentParser.evaluate( path, target ); |
| | - final var sourceNode = DocumentParser.evaluate( "/html/body", sourceDoc ); |
| | - final var children = sourceNode.getChildNodes(); |
| | + forEachChild( |
| | + children, child -> { |
| | + if( child.getNodeType() == Node.ELEMENT_NODE ) { |
| | + final var name = child.getNodeName(); |
| | + final var targetElement = find( target, name ); |
| | |
| | - for( var i = 0; i < children.getLength(); i++ ) { |
| | - final var childNode = children.item( i ); |
| | - final var importedNode = target.importNode( childNode, true ); |
| | + append( child, target, targetElement ); |
| | + } |
| | + } |
| | + ); |
| | |
| | - targetNode.appendChild( importedNode ); |
| | - } |
| | } |
| | - catch( Exception ex ) { |
| | + catch( final Exception ex ) { |
| | clue( ex ); |
| | + } |
| | + } |
| | + |
| | + private Node find( final Document document, final String name ) { |
| | + assert document != null; |
| | + assert name != null; |
| | + assert !name.isBlank(); |
| | + |
| | + try { |
| | + // Both documents are well-formed at this point. |
| | + return DocumentParser.evaluate( "//" + name, document ); |
| | + } |
| | + catch( final Exception ex ) { |
| | + // Implies that the head/body elements are missing from the document. |
| | + final var element = document.createElement( name ); |
| | + document.getDocumentElement().appendChild( element ); |
| | + |
| | + return element; |
| | } |
| | + } |
| | + |
| | + private void append( |
| | + final Node source, |
| | + final Document targetDoc, |
| | + final Node targetNode |
| | + ) { |
| | + assert source != null; |
| | + assert targetDoc != null; |
| | + assert targetNode != null; |
| | + |
| | + final var children = source.getChildNodes(); |
| | + |
| | + forEachChild( |
| | + children, child -> { |
| | + final var imported = targetDoc.importNode( child, true ); |
| | + targetNode.appendChild( imported ); |
| | + } |
| | + ); |
| | } |
| | + |
| | + private void forEachChild( |
| | + final NodeList children, |
| | + final Consumer<Node> action |
| | + ) { |
| | + assert children != null; |
| | + assert action != null; |
| | + |
| | + final var childCount = children.getLength(); |
| | |
| | + for( var i = 0; i < childCount; i++ ) { |
| | + action.accept( children.item( i ) ); |
| | + } |
| | + } |
| | |
| | /** |