Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Merges two HTML nodes into a single XHTML document

AuthorDaveJarvis <email>
Date2025-08-23 01:26:46 GMT-0700
Commit2c88469c1d9decb85ff2f426be0d77799a9bb33f
Parent5de7647
src/main/java/com/keenwrite/dom/DocumentParser.java
assert xhtml != null;
+ String result = "";
+
try( final var writer = new StringWriter() ) {
- final var result = new StreamResult( writer );
+ final var stream = new StreamResult( writer );
- transform( xhtml, result );
+ transform( xhtml, stream );
- return writer.toString();
+ result = writer.toString();
}
catch( final Exception ex ) {
clue( ex );
- return "";
}
+
+ return result;
}
src/main/java/com/keenwrite/processors/html/XhtmlProcessor.java
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 ) );
+ }
+ }
/**
Delta78 lines added, 16 lines removed, 62-line increase