Skip to content

Commit a23433c

Browse files
authored
TIKA-4663 - make markdown the default content handler in tika-app, tika-server, and the async CLI (#2877)
* TIKA-4663 - make markdown the default content handler in tika-app, tika-server, and the async CLI
1 parent de9433e commit a23433c

18 files changed

Lines changed: 97 additions & 28 deletions

File tree

CHANGES.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
Release 4.0.0-beta-1 - unreleased
2+
3+
BREAKING CHANGES
4+
5+
* The default content handler is now Markdown. tika-app, tika-server
6+
(the /tika and /rmeta endpoints), and the async/pipes CLI now emit
7+
Markdown content by default instead of XHTML/XML (plain text for the
8+
async CLI). Request the previous format explicitly, e.g. tika-app
9+
-x/--xml, the server /tika/xml and /rmeta/xml paths (or the
10+
X-Tika-Handler header), and the async CLI --handler x (TIKA-4663).
11+
12+
113
Release 4.0.0-alpha-1 - 5/4/2026
214

315
BREAKING CHANGES

docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ java -jar tika-app-<version>.jar [option...] [file...]
4040

4141
If you have build scripts or container images that drop in just the jar, update them to unpack the zip and run from inside it.
4242

43+
== Default content handler: XHTML/XML -> Markdown
44+
45+
In 3.x the default content handler produced XHTML/XML. In 4.x the default is **Markdown** everywhere:
46+
47+
* `tika-app` outputs Markdown by default (was XHTML). Pass `-x`/`--xml`, `-h`/`--html`, or `-t`/`--text` to choose another format.
48+
* `tika-server` — the `/tika` and `/rmeta` endpoints return Markdown content by default (was XHTML/XML). Use an explicit handler path (`/tika/xml`, `/rmeta/xml`, ...) or the `X-Tika-Handler` header to choose another format.
49+
* The async/pipes CLI emits Markdown by default (was plain text). Use `--handler x` (etc.) to choose another format.
50+
51+
If you parse the extracted content programmatically and expect XHTML/XML, request it explicitly as shown above (TIKA-4663).
52+
4353
== Configuration: XML to JSON
4454

4555
Tika 4.x uses JSON configuration files instead of XML. The legacy `tika-config.xml` format

docs/modules/ROOT/pages/pipes/getting-started.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ java -jar tika-app.jar -i /data/input -o /data/output --handler t
5353
java -jar tika-app.jar -i /data/input -o /data/output -Z
5454
----
5555

56-
Handler types: `t` (text), `h` (html), `x` (xml), `m` (markdown), `b` (body), `i` (ignore/metadata only).
56+
Handler types: `t` (text), `h` (html), `x` (xml), `m` (markdown), `b` (body), `i` (ignore/metadata only). The default is `m` (markdown).
5757

5858
== JSON Configuration
5959

docs/modules/ROOT/pages/pipes/parse-modes.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ and applies to all modes that produce content (`RMETA`, `CONCATENATE`, `CONTENT_
6969

7070
Accepted `type` values: `TEXT`, `HTML`, `XML`, `MARKDOWN`, `BODY`, `IGNORE`. The CLI
7171
`--handler` flag uses single-letter shortcuts (`t`, `h`, `x`, `m`, `b`, `i`) that map onto
72-
these values.
72+
these values. If unset, the default is `MARKDOWN`.
7373

7474
[cols="1,1,2"]
7575
|===

docs/modules/ROOT/pages/using-tika/cli/index.adoc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ options see <<_tika_pipes_processing,Tika Pipes Processing>> below.
118118
|Option |Description
119119

120120
|`-x` or `--xml`
121-
|Output XHTML content (default)
121+
|Output XHTML content
122122

123123
|`-h` or `--html`
124124
|Output HTML content
@@ -127,7 +127,7 @@ options see <<_tika_pipes_processing,Tika Pipes Processing>> below.
127127
|Output plain text content (body)
128128

129129
|`--md`
130-
|Output Markdown content (body)
130+
|Output Markdown content (body) (default)
131131

132132
|`-T` or `--text-main`
133133
|Output plain text — main content only, via the boilerpipe handler
@@ -145,7 +145,7 @@ options see <<_tika_pipes_processing,Tika Pipes Processing>> below.
145145
|Output metadata in XMP
146146

147147
|`-J` or `--jsonRecursive`
148-
|Output metadata and content from all embedded files. Combine with `-x`/`-h`/`-t`/`-m` to choose the content type (default: `-x`).
148+
|Output metadata and content from all embedded files. Combine with `-x`/`-h`/`-t`/`-m` to choose the content type (default: `--md`).
149149

150150
|`-r` or `--pretty-print`
151151
|For JSON, XML, and XHTML output, add newlines and whitespace for readability.
@@ -378,7 +378,7 @@ This processes all files in the input directory and writes JSON metadata
378378
|Option |Description
379379

380380
|`--handler=<X>`
381-
|Content handler type: `t`=text, `h`=html, `x`=xml, `m`=markdown, `b`=body, `i`=ignore. Default: `t`.
381+
|Content handler type: `t`=text, `h`=html, `x`=xml, `m`=markdown, `b`=body, `i`=ignore. Default: `m`.
382382

383383
|`--concatenate`
384384
|Concatenate content from all embedded documents into a single content field.

docs/modules/ROOT/pages/using-tika/server/index.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ For the root `/tika` PUT endpoint you can also pick the handler with a header:
117117
curl -T document.pdf -H "X-Tika-Handler: markdown" http://localhost:9998/tika
118118
----
119119

120-
Accepted values: `text`, `html`, `xml`, `markdown` (or `md`), `body`, `ignore`.
120+
Accepted values: `text`, `html`, `xml`, `markdown` (or `md`), `body`, `ignore`. The default is `markdown`.
121121

122122
=== Recursive Metadata (`/rmeta`)
123123

@@ -126,7 +126,7 @@ array of metadata objects. The handler controls the content field of each entry:
126126

127127
[source,bash]
128128
----
129-
curl -T document.pdf http://localhost:9998/rmeta # default: text
129+
curl -T document.pdf http://localhost:9998/rmeta # default: markdown
130130
curl -T document.pdf http://localhost:9998/rmeta/text
131131
curl -T document.pdf http://localhost:9998/rmeta/html
132132
curl -T document.pdf http://localhost:9998/rmeta/xml

tika-app/src/main/java/org/apache/tika/cli/AsyncHelper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ public static String[] translateArgs(String[] args) {
7878
// Translate TikaCLI xml output to the TikaAsyncCLI handler type.
7979
argList.add("--handler");
8080
argList.add("x");
81+
} else if (arg.equals("--md")) {
82+
// Translate TikaCLI markdown output to the TikaAsyncCLI handler type.
83+
argList.add("--handler");
84+
argList.add("m");
8185
} else if (arg.equals("-J") || arg.equals("--jsonRecursive")) {
8286
// TikaAsyncCLI always outputs JSON with recursive metadata (RMETA mode)
8387
// This is already the default, so we just skip this arg

tika-app/src/main/java/org/apache/tika/cli/TikaCLI.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ protected ContentHandler getContentHandler(OutputStream output, Metadata metadat
243243
return getTransformerHandler(output, "xml", encoding, prettyPrint);
244244
}
245245
};
246-
private OutputType type = XML;
246+
private OutputType type = MARKDOWN;
247247
private final OutputType HTML = new OutputType() {
248248
@Override
249249
protected ContentHandler getContentHandler(OutputStream output, Metadata metadata) throws Exception {
@@ -793,6 +793,8 @@ private ContentHandlerFactory getContentHandlerFactory(OutputType type) {
793793
handlerType = BasicContentHandlerFactory.HANDLER_TYPE.TEXT;
794794
} else if (type.equals(TEXT_MAIN)) {
795795
handlerType = BasicContentHandlerFactory.HANDLER_TYPE.BODY;
796+
} else if (type.equals(MARKDOWN)) {
797+
handlerType = BasicContentHandlerFactory.HANDLER_TYPE.MARKDOWN;
796798
} else if (type.equals(METADATA)) {
797799
handlerType = BasicContentHandlerFactory.HANDLER_TYPE.IGNORE;
798800
}
@@ -823,18 +825,18 @@ private void usage() {
823825
out.println(" writing the JSON to stdout. Redirect to save, e.g.:");
824826
out.println(" --convert-config-xml-to-json=tika-config.xml > tika-config.json");
825827
out.println("");
826-
out.println(" -x or --xml Output XHTML content (default)");
828+
out.println(" -x or --xml Output XHTML content");
827829
out.println(" -h or --html Output HTML content");
828830
out.println(" -t or --text Output plain text content (body)");
829-
out.println(" --md Output Markdown content (body)");
831+
out.println(" --md Output Markdown content (body) (default)");
830832
out.println(" -T or --text-main Output plain text content (main content only via boilerpipe handler)");
831833
out.println(" -A or --text-all Output all text content");
832834
out.println(" -m or --metadata Output only metadata");
833835
out.println(" -j or --json Output metadata in JSON");
834836
out.println(" -y or --xmp Output metadata in XMP");
835837
out.println(" -J or --jsonRecursive Output metadata and content from all");
836838
out.println(" embedded files (choose content type");
837-
out.println(" with -x, -h, -t or -m; default is -x)");
839+
out.println(" with -x, -h, -t or -m; default is --md)");
838840
out.println(" -a or --async Run Tika in async mode; must specify details in a" + " tikaConfig file");
839841
out.println(" -l or --language Output only language");
840842
out.println(" -d or --detect Detect document type");
@@ -915,7 +917,7 @@ private void usage() {
915917
out.println(" -c, --config=<file> Tika config file (--config=<file> also accepted)");
916918
out.println(" -p, --pluginsDir Plugins directory");
917919
out.println(" --fileList File list (one path per line, relative to -i or absolute)");
918-
out.println(" --handler Handler type: t=text, h=html, x=xml, m=markdown, b=body, i=ignore");
920+
out.println(" --handler Handler type: t=text, h=html, x=xml, m=markdown, b=body, i=ignore (default: m)");
919921
out.println(" --concatenate Concatenate content from all embedded documents");
920922
out.println(" --content-only Output only extracted content (no JSON wrapper); implies --concatenate");
921923
out.println(" --on-exists Behavior when an output file exists: exception (default), replace, skip");

tika-app/src/test/java/org/apache/tika/cli/AsyncHelperTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ public void testXmlHandler() throws Exception {
5757
assertArrayEquals(expected, AsyncHelper.translateArgs(args));
5858
}
5959

60+
@Test
61+
public void testMarkdownHandler() throws Exception {
62+
String[] args = new String[]{"--md", "input", "output"};
63+
String[] expected = new String[]{"--handler", "m", "input", "output"};
64+
assertArrayEquals(expected, AsyncHelper.translateArgs(args));
65+
}
66+
6067
@Test
6168
public void testExtractLongFormTranslatedToZ() throws Exception {
6269
// TIKA-4736: tika-app's --extract is the long form of -z. It must be

tika-app/src/test/java/org/apache/tika/cli/TikaCLITest.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ public void testDefaultPDFIncrementalUpdateSettings() throws Exception {
259259

260260
@Test
261261
public void testExtractJavascript() throws Exception {
262-
String json = getParamOutContent("-J", resourcePrefix + "testPDFPackage.pdf");
262+
String json = getParamOutContent("-J", "-x", resourcePrefix + "testPDFPackage.pdf");
263263
assertTrue(json.contains("type=\\\"PDActionJavaScript\\\""));
264264
assertTrue(json.contains("MACRO"));
265265
assertTrue(json.contains("NAMES_TREE"));
@@ -341,7 +341,7 @@ public void testDetectOutput() throws Exception {
341341
*/
342342
@Test
343343
public void testListMetModels() throws Exception {
344-
String content = getParamOutContent("--list-met-models", resourcePrefix + "alice.cli.test");
344+
String content = getParamOutContent("--list-met-models", "-x", resourcePrefix + "alice.cli.test");
345345
assertTrue(content.contains("text/plain"));
346346
}
347347

@@ -663,7 +663,7 @@ public void testDefaultConfigException() throws Exception {
663663

664664
@Test
665665
public void testConfig() throws Exception {
666-
String content = getParamOutContent("--config=" + CONFIGS_DIR.toString() + "/tika-config1.json", resourcePrefix + "bad_xml.xml");
666+
String content = getParamOutContent("--config=" + CONFIGS_DIR.toString() + "/tika-config1.json", "-x", resourcePrefix + "bad_xml.xml");
667667
assertTrue(content.contains("apple"));
668668
assertTrue(content.contains("org.apache.tika.parser.html.JSoupParser"));
669669
}
@@ -679,8 +679,12 @@ public void testJsonRecursiveMetadataParserMetadataOnly() throws Exception {
679679

680680
@Test
681681
public void testJsonRecursiveMetadataParserDefault() throws Exception {
682+
// TIKA-4663: default handler is markdown, so recursive content is markdown, not XHTML.
682683
String content = getParamOutContent("-J", "-r", resourcePrefix + "test_recursive_embedded.docx");
683-
assertTrue(content.contains("\"X-TIKA:content\" : \"<html xmlns=\\\"http://www.w3.org/1999/xhtml"));
684+
assertFalse(content.contains("<html xmlns=\\\"http://www.w3.org/1999/xhtml"),
685+
"default recursive content should be markdown, not XHTML");
686+
assertTrue(content.contains("# embed1.zip"),
687+
"default recursive content should be markdown (heading syntax)");
684688
}
685689

686690
@Test

0 commit comments

Comments
 (0)