Quick Start
Use Xberg’s core API through extract, extract_batch, ExtractInput, and the
ExtractionResult envelope. Install your binding first:
Installation.
TypeScript users: @xberg-io/xberg for Node.js, @xberg-io/xberg-wasm for browsers and edge runtimes — see Language Support.
Your First Extraction
Section titled “Your First Extraction”Pass an ExtractInput with kind = "uri" to extract a local path, file:// URI,
or HTTP(S) URL. extract returns an ExtractionResult with a results list:
Tests URI extraction API
import asynciofrom xberg import extract, ExtractInput, ExtractInputKind
async def main() -> None: input = ExtractInput(kind=ExtractInputKind("uri"), uri="https://example.com/pdf/fake_memo.pdf") result = await extract(input) print(result.results[0].content)
asyncio.run(main())Tests URI extraction API
import { ExtractInput, ExtractInputKind, extract } from "@xberg-io/xberg";async function main() { const input: ExtractInput = { kind: ExtractInputKind.Uri, uri: "https://example.com/pdf/fake_memo.pdf" }; const result = await extract(input); console.log(result.results?.[0]?.content);}
void main();Tests URI extraction API
import { WasmExtractInput, WasmExtractInputKind, extract } from "@xberg-io/xberg-wasm";async function main() { const input: WasmExtractInput = (() => { const _u0 = WasmExtractInput.default(); _u0.kind = WasmExtractInputKind.Uri; _u0.uri = "https://example.com/pdf/fake_memo.pdf"; return _u0; })(); const result = await extract(input, undefined); console.log(result.results[0].content);}
void main();Tests URI extraction API
use xberg::extract;use xberg::ExtractInput;
#[tokio::main]async fn main() { let input_json: serde_json::Value = serde_json::from_str(r#"{"kind":"uri","uri":"https://example.com/pdf/fake_memo.pdf"}"#).unwrap(); let input = serde_json::from_value::<ExtractInput>(input_json).unwrap(); let config = Default::default(); let result = extract(input, &config).await.expect("call failed"); println!("{:?}", result.results[0].content);}Tests URI extraction API
package main
import ( "fmt" xberg "github.com/xberg-io/xberg/packages/go")
func ptr[T any](value T) *T { return &value }func main() { input := xberg.ExtractInput{ Kind: ptr(xberg.ExtractInputKindURI), URI: ptr(`https://example.com/pdf/fake_memo.pdf`), } config := xberg.ExtractionConfig{} result, err := xberg.Extract(input, config) if err != nil { panic(err) } fmt.Printf("%+v\n", result.Results[0].Content)}Tests URI extraction API
import io.xberg.*;
public final class Example { public static void main(String[] args) throws Exception { var inputJson = "{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}"; var input = JsonUtil.fromJson(inputJson, ExtractInput.class); var result = Xberg.extract(input, ExtractionConfig.builder().build()); System.out.println(result.results().get(0).content()); }}Tests URI extraction API
import io.xberg.*import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
fun main() = kotlinx.coroutines.runBlocking { val mapper = jacksonObjectMapper().setPropertyNamingStrategy(com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE) val input = mapper.readValue("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", ExtractInput::class.java) val configDefault = mapper.readValue("{\"url\":{\"crawl\":{\"ssrf\":{}}}}", ExtractionConfig::class.java) val result = Xberg.extract(input, configDefault) println(result.results.first().content)}Tests URI extraction API
using System;using System.Text.Json;using Xberg;
var ConfigOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };var result = await XbergConverter.ExtractAsync(new ExtractInput { Kind = JsonSerializer.Deserialize<ExtractInputKind>("\"uri\"", ConfigOptions)!, Uri = "https://example.com/pdf/fake_memo.pdf" }, new ExtractionConfig());Console.WriteLine(result.Results[0].Content);Tests URI extraction API
import Xberg
let result = try await Xberg.extract("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", "{}")debugPrint(result.results()[0].content())Tests URI extraction API
require "xberg"result = Xberg.extract(Xberg::ExtractInput.new(kind: 'uri', uri: 'https://example.com/pdf/fake_memo.pdf'))puts result.results[0].content.inspectTests URI extraction API
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Xberg\Xberg;use Xberg\ExtractInput;$input = \Xberg\ExtractInput::from_json(json_encode(["kind" => "uri", "uri" => "https://example.com/pdf/fake_memo.pdf"]));$result = Xberg::extract($input, null);var_dump($result->getResults()[0]->content);Tests URI extraction API
input_value = %Xberg.ExtractInput{kind: "uri", uri: "https://example.com/pdf/fake_memo.pdf"}result = Xberg.extract_async(input_value)IO.inspect(Enum.at(result.results, 0).content)Tests URI extraction API
import 'dart:io';import 'package:xberg/xberg.dart';import 'package:xberg/src/xberg_bridge_generated/frb_generated.dart' show RustLib;Future<void> main() async { await RustLib.init(); try { final input = await createExtractInputFromJson(json: '{"kind":"uri","uri":"https://example.com/pdf/fake_memo.pdf"}'); final config = await createExtractionConfigFromJson(json: '{}'); final result = await XbergBridge.extract(input, config: config); stdout.writeln(result.results[0].content); } finally { RustLib.dispose(); }}Tests URI extraction API
const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { const _result_json = try xberg.extract("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", "{}"); defer std.heap.c_allocator.free(_result_json); std.debug.print("{s}\n", .{_result_json});
}Tests URI extraction API
#include <assert.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "xberg.h"
int main(void) { XBERGAlefHandle input_handle = xberg_extract_input_from_json("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}"); XBERGAlefHandle result = xberg_extract(input_handle, 0); xberg_extract_input_free(input_handle); xberg_extraction_result_free(result); return EXIT_SUCCESS;}For the command line:
# Extract to stdoutxberg extract document.pdf
# Save to file using shell redirectionxberg extract document.pdf > output.txt
# Extract with JSON format (includes metadata)xberg extract document.pdf --format jsonHandle Errors
Section titled “Handle Errors”Handle extraction failures through your binding’s typed error surface. This example rejects an unsupported MIME type; missing files, parse failures, and OCR failures use the same language-appropriate error path:
Error when extracting with unsupported MIME type
import asynciofrom pathlib import Pathfrom xberg import extract, ExtractInput, FileExtractionConfig, ExtractInputKindfrom xberg._xberg import ExtractionConfigfrom xberg import XbergError
async def main() -> None: try: input = ExtractInput(bytes=Path("text/plain.txt").read_bytes(), config=FileExtractionConfig(), filename="plain.txt", kind=ExtractInputKind("bytes"), mime_type="application/x-nonexistent") config = ExtractionConfig.from_json("{}") await extract(input, config) except XbergError as error: print(f"{type(error).__name__}: {error}")
asyncio.run(main())Error when extracting with unsupported MIME type
import { ExtractInput, ExtractInputKind, extract } from "@xberg-io/xberg";async function main() { const input: ExtractInput = { bytes: await (await import("node:fs/promises")).readFile("text/plain.txt"), config: { }, filename: "plain.txt", kind: ExtractInputKind.Bytes, mimeType: "application/x-nonexistent" }; try { await extract(input); } catch (error) { if (error instanceof Error) { console.error(`${error.name}: ${error.message}`); } }}
void main();Error when extracting with unsupported MIME type
import { WasmExtractInput, WasmExtractInputKind, WasmFileExtractionConfig, extract } from "@xberg-io/xberg-wasm";async function main() { const input: WasmExtractInput = await (async () => { const _u0 = WasmExtractInput.default(); _u0.bytes = await (await import("node:fs/promises")).readFile("text/plain.txt"); _u0.config = await (async () => { const _u1 = WasmFileExtractionConfig.default(); return _u1; })(); _u0.filename = "plain.txt"; _u0.kind = WasmExtractInputKind.Bytes; _u0.mimeType = "application/x-nonexistent"; return _u0; })(); try { await extract(input, { }); } catch (error) { console.error(String(error)); }}
void main();Error when extracting with unsupported MIME type
use xberg::extract;use xberg::ExtractInput;
#[tokio::main]async fn main() { let mut input_json: serde_json::Value = serde_json::from_str(r#"{"bytes":"text/plain.txt","config":{},"filename":"plain.txt","kind":"bytes","mime_type":"application/x-nonexistent"}"#).unwrap(); let input_file_0 = std::fs::read(r#"text/plain.txt"#).expect("file read failed"); *input_json.pointer_mut(r#"/bytes"#).expect("docs file field missing") = serde_json::json!(input_file_0); let input = serde_json::from_value::<ExtractInput>(input_json).unwrap(); let config_json: serde_json::Value = serde_json::from_str(r#"{}"#).unwrap(); let config = serde_json::from_value(config_json).unwrap(); let result = extract(input, &config).await; match result { Ok(value) => println!("{:?}", value), Err(error) => println!("{error}"), }}Error when extracting with unsupported MIME type
package main
import ( "errors" "fmt" xberg "github.com/xberg-io/xberg/packages/go" "os")
func ptr[T any](value T) *T { return &value }func mustReadFile(path string) []byte { content, err := os.ReadFile(path) if err != nil { panic(err) } return content}func main() { input := xberg.ExtractInput{ Kind: ptr(xberg.ExtractInputKindBytes), Bytes: mustReadFile(`text/plain.txt`), MimeType: ptr(`application/x-nonexistent`), Filename: ptr(`plain.txt`), Config: &xberg.FileExtractionConfig{}, } config := xberg.ExtractionConfig{} _, err := xberg.Extract(input, config) var typedError xberg.Error if errors.As(err, &typedError) { fmt.Fprintf(os.Stderr, "%T: %v\n", typedError, typedError) }}Error when extracting with unsupported MIME type
import io.xberg.*;
public final class Example { public static void main(String[] args) throws Exception { try { var inputFile0 = java.util.Base64.getEncoder().encodeToString( java.nio.file.Files.readAllBytes(java.nio.file.Path.of("text/plain.txt")) ); var inputJson = "{\"bytes\":\"__ALEF_DOC_FILE_0__\",\"config\":{},\"filename\":\"plain.txt\",\"kind\":\"bytes\",\"mime_type\":\"application/x-nonexistent\"}"; inputJson = inputJson.replace("__ALEF_DOC_FILE_0__", inputFile0); var input = JsonUtil.fromJson(inputJson, ExtractInput.class); var configJson = "{}"; var config = JsonUtil.fromJson(configJson, ExtractionConfig.class); var result = Xberg.extract(input, config); System.out.println(result); } catch (XbergRsException error) { System.err.println(error.getClass().getSimpleName() + ": " + error.getMessage()); } }}Error when extracting with unsupported MIME type
import io.xberg.*import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
fun main() = kotlinx.coroutines.runBlocking { val mapper = jacksonObjectMapper().setPropertyNamingStrategy(com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE) try { val inputFile0 = java.util.Base64.getEncoder().encodeToString(java.nio.file.Files.readAllBytes(java.nio.file.Path.of("text/plain.txt"))) val input = mapper.readValue("{\"bytes\":\"__ALEF_DOC_FILE_0__\",\"config\":{},\"filename\":\"plain.txt\",\"kind\":\"bytes\",\"mime_type\":\"application/x-nonexistent\"}".replace("__ALEF_DOC_FILE_0__", inputFile0), ExtractInput::class.java) val config = mapper.readValue("{\"url\":{\"crawl\":{\"ssrf\":{}}}}", ExtractionConfig::class.java) val result = Xberg.extract(input, config) } catch (error: Exception) { System.err.println("${error::class.simpleName}: ${error.message}") }}Error when extracting with unsupported MIME type
using System;using System.Text.Json;using Xberg;
var ConfigOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };try{var result = await XbergConverter.ExtractAsync(new ExtractInput { Bytes = System.IO.File.ReadAllBytes("text/plain.txt"), Config = new FileExtractionConfig(), Filename = "plain.txt", Kind = JsonSerializer.Deserialize<ExtractInputKind>("\"bytes\"", ConfigOptions)!, MimeType = "application/x-nonexistent" }, new ExtractionConfig());}catch (Exception error){ Console.Error.WriteLine($"{error.GetType().Name}: {error.Message}");}Error when extracting with unsupported MIME type
import Xberg
do { _ = try await Xberg.extract("{\"bytes\":\"text/plain.txt\",\"config\":{},\"filename\":\"plain.txt\",\"kind\":\"bytes\",\"mime_type\":\"application/x-nonexistent\"}", "{}")} catch { print("\(type(of: error)): \(error)")}Error when extracting with unsupported MIME type
require "xberg"begin result = Xberg.extract(Xberg::ExtractInput.new(bytes: File.binread('text/plain.txt').bytes, config: { }, filename: 'plain.txt', kind: 'bytes', mime_type: 'application/x-nonexistent'), { })rescue StandardError => error warn "#{error.class}: #{error.message}"endError when extracting with unsupported MIME type
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Xberg\Xberg;use Xberg\ExtractInput;$input = \Xberg\ExtractInput::from_json(json_encode(["bytes" => "text/plain.txt", "config" => [], "filename" => "plain.txt", "kind" => "bytes", "mimeType" => "application/x-nonexistent"]));try { Xberg::extract($input, []);} catch (Throwable $error) { echo $error::class . ': ' . $error->getMessage() . "\n";}Error when extracting with unsupported MIME type
try do input_value = %Xberg.ExtractInput{bytes: :binary.bin_to_list(File.read!("text/plain.txt")), config: %{}, filename: "plain.txt", kind: "bytes", mime_type: "application/x-nonexistent"} result = Xberg.extract_async(input_value, "{}")rescue error -> IO.puts(:stderr, "#{inspect(error.__struct__)}: #{Exception.message(error)}")endError when extracting with unsupported MIME type
import 'dart:io';import 'package:xberg/xberg.dart';import 'package:xberg/src/xberg_bridge_generated/frb_generated.dart' show RustLib;Future<void> main() async { await RustLib.init(); try { try { final input = await createExtractInputFromJson(json: '{"bytes":"text/plain.txt","config":{},"filename":"plain.txt","kind":"bytes","mime_type":"application/x-nonexistent"}'); final config = await createExtractionConfigFromJson(json: '{}'); final result = await XbergBridge.extract(input, config: config); stdout.writeln(result); } on XbergError catch (error) { stderr.writeln('${error.runtimeType}: $error'); } } finally { RustLib.dispose(); }}Error when extracting with unsupported MIME type
const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { var gpa: std.heap.DebugAllocator(.{}) = .init; defer _ = gpa.deinit(); const allocator = gpa.allocator();
var input_file_0_threaded = std.Io.Threaded.init(allocator, .{});defer input_file_0_threaded.deinit();const input_file_0_io = input_file_0_threaded.io();const input_file_0 = try std.Io.Dir.cwd().readFileAlloc(input_file_0_io, "text/plain.txt", allocator, .unlimited);defer allocator.free(input_file_0); const input_file_0_json = try std.json.Stringify.valueAlloc(allocator, input_file_0, .{ .emit_strings_as_arrays = true });defer allocator.free(input_file_0_json); const input_json_0 = try std.mem.replaceOwned(u8, allocator, "{\"bytes\":\"__ALEF_DOC_FILE_0__\",\"config\":{},\"filename\":\"plain.txt\",\"kind\":\"bytes\",\"mime_type\":\"application/x-nonexistent\"}", "\"__ALEF_DOC_FILE_0__\"", input_file_0_json);defer allocator.free(input_json_0); if (xberg.extract(input_json_0, "{}")) |_| { return error.TestUnexpectedResult; } else |err| { std.debug.print("call failed as expected: {s}\n", .{@errorName(err)}); }}Error when extracting with unsupported MIME type
#include <assert.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "xberg.h"
int main(void) { const char *input_json_base = "{\"bytes\":\"__ALEF_DOC_FILE_0__\",\"config\":{},\"filename\":\"plain.txt\",\"kind\":\"bytes\",\"mime_type\":\"application/x-nonexistent\"}"; FILE *input_file_0 = fopen("text/plain.txt", "rb"); if (input_file_0 == NULL) return EXIT_FAILURE; fseek(input_file_0, 0, SEEK_END); long input_size_0 = ftell(input_file_0); if (input_size_0 < 0) { fclose(input_file_0); return EXIT_FAILURE; } rewind(input_file_0); uint8_t *input_bytes_0 = malloc(input_size_0 > 0 ? (size_t)input_size_0 : 1); if (input_bytes_0 == NULL) { fclose(input_file_0); return EXIT_FAILURE; } if (fread(input_bytes_0, 1, (size_t)input_size_0, input_file_0) != (size_t)input_size_0) { free(input_bytes_0); fclose(input_file_0); return EXIT_FAILURE; } fclose(input_file_0); char *input_bytes_json_0 = malloc((size_t)input_size_0 * 4 + 3); if (input_bytes_json_0 == NULL) { free(input_bytes_0); return EXIT_FAILURE; } size_t input_offset_0 = 0; input_bytes_json_0[input_offset_0++] = '['; for (long i = 0; i < input_size_0; ++i) { input_offset_0 += (size_t)snprintf(input_bytes_json_0 + input_offset_0, 5, "%s%u", i == 0 ? "" : ",", input_bytes_0[i]); } input_bytes_json_0[input_offset_0++] = ']'; input_bytes_json_0[input_offset_0] = '\0'; free(input_bytes_0); const char *input_marker_0 = "\"__ALEF_DOC_FILE_0__\""; const char *input_position_0 = strstr(input_json_base, input_marker_0); if (input_position_0 == NULL) { free(input_bytes_json_0); return EXIT_FAILURE; } size_t input_prefix_0 = (size_t)(input_position_0 - input_json_base); size_t input_json_size_0 = strlen(input_json_base) - strlen(input_marker_0) + strlen(input_bytes_json_0) + 1; char *input_json_0 = malloc(input_json_size_0); if (input_json_0 == NULL) { free(input_bytes_json_0); return EXIT_FAILURE; } snprintf(input_json_0, input_json_size_0, "%.*s%s%s", (int)input_prefix_0, input_json_base, input_bytes_json_0, input_position_0 + strlen(input_marker_0)); free(input_bytes_json_0); XBERGAlefHandle input_handle = xberg_extract_input_from_json(input_json_0); free(input_json_0); XBERGAlefHandle config_handle = xberg_extraction_config_from_json("{}"); XBERGAlefHandle result = xberg_extract(input_handle, config_handle); if (result != 0) { return EXIT_FAILURE; } xberg_extract_input_free(input_handle); xberg_extraction_config_free(config_handle); return EXIT_SUCCESS;}OCR for Scanned Documents
Section titled “OCR for Scanned Documents”Xberg runs OCR automatically when it detects an image or scanned PDF. You can also force OCR on any document:
#include "xberg.h"#include <stdio.h>
int main(void) { const char *config_json = "{" "\"ocr\": {\"tesseract\": {\"language\": \"eng\"}}" "}";
XBERGAlefHandle config = xberg_extraction_config_from_json(config_json); if (config == 0) { fprintf(stderr, "config parse failed (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); return 1; }
XBERGAlefHandle input = xberg_extract_input_from_uri("scanned.png"); if (input == 0) { fprintf(stderr, "Failed to create input (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); xberg_extraction_config_free(config); return 1; }
XBERGAlefHandle result = xberg_extract(input, config); if (result != 0) { char *results = xberg_extraction_result_results(result); if (results) { printf("OCR results: %s\n", results); } xberg_free_string(results); } else { fprintf(stderr, "OCR error (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); }
xberg_extract_input_free(input); xberg_extraction_result_free(result); xberg_extraction_config_free(config); return 0;}using Xberg;
var config = new ExtractionConfig{ ForceOcr = true, Ocr = new OcrConfig { Backend = "tesseract", Language = new List<string> { "eng" }, },};
var result = (await XbergConverter.ExtractAsync(ExtractInput.FromUri("scanned.pdf"), config)).Results[0];Console.WriteLine(result.Content);Console.WriteLine(result.DetectedLanguages);import 'package:xberg/xberg.dart';
Future<void> main() async { // `ExtractionConfig` is a generated data class with no defaults, so build it // from JSON: every field you omit keeps its Rust-side default value. final config = await createExtractionConfigFromJson(json: '''{ "force_ocr": true, "ocr": { "backend": "tesseract", "language": ["eng"] }}''');
const input = ExtractInput( kind: ExtractInputKind.uri, uri: 'scanned.pdf', ); final output = await XbergBridge.extract(input, config: config); final document = output.results.first;
print(document.content);}package main
import ( "log"
"github.com/xberg-io/xberg/packages/go")
func main() { cfg := xberg.ExtractionConfig{ Ocr: &xberg.OcrConfig{ Backend: xberg.Ptr("tesseract"), Language: []string{"eng"}, }, }
input := xberg.ExtractInputFromURI("scanned.pdf") result, err := xberg.Extract(*input, cfg) if err != nil { log.Fatalf("extract failed: %v", err) } log.Println(len(result.Results[0].Content))}import io.xberg.ExtractInput;import io.xberg.ExtractInputKind;import io.xberg.ExtractedDocument;import io.xberg.ExtractionConfig;import io.xberg.ExtractionResult;import io.xberg.OcrConfig;import io.xberg.Xberg;import io.xberg.XbergRsException;import java.util.List;
public class Main { public static void main(String[] args) { try { ExtractionConfig config = ExtractionConfig.builder() .withForceOcr(true) .withOcr(OcrConfig.builder() .withBackend("tesseract") .withLanguage(List.of("eng")) .build()) .build();
ExtractInput input = ExtractInput.builder() .withKind(ExtractInputKind.URI) .withUri("scanned.pdf") .build();
ExtractionResult output = Xberg.extract(input, config); ExtractedDocument document = output.results().get(0); System.out.println(document.content()); } catch (XbergRsException e) { System.err.println("Extraction failed: " + e.getMessage()); } }}import io.xberg.*
private const val DEFAULT_MAX_ARCHIVE_DEPTH = 3Lprivate const val DEFAULT_EXTRACTION_TIMEOUT_SECS = 600Lprivate const val DEFAULT_MAX_EMBEDDED_FILE_BYTES = 50L * 1024L * 1024L
fun main() { val ocr = OcrConfig(backend = "tesseract", language = listOf("eng")) val config = ExtractionConfig( ocr = ocr, extractionTimeoutSecs = DEFAULT_EXTRACTION_TIMEOUT_SECS, maxEmbeddedFileBytes = DEFAULT_MAX_EMBEDDED_FILE_BYTES, url = UrlExtractionConfig(crawl = CrawlConfig(ssrf = SsrfPolicy())), maxArchiveDepth = DEFAULT_MAX_ARCHIVE_DEPTH, )
val resultOutput = Xberg.extract( ExtractInput(kind = ExtractInputKind.URI, uri = "scanned.pdf"), config, ) val result = resultOutput.results.first() println(result.content)}import asynciofrom xberg import ExtractInput, extract, ExtractionConfig, OcrConfig
async def main() -> None: config: ExtractionConfig = ExtractionConfig( ocr=OcrConfig(backend="tesseract", language=["eng"]) )
result = await extract(ExtractInput(uri="scanned.pdf"), config)
content: str = result.results[0].content preview: str = content[:100] total_length: int = len(content)
print(f"Extracted content (preview): {preview}") print(f"Total characters: {total_length}")
asyncio.run(main())require 'xberg'
ocr_config = Xberg::OcrConfig.new( backend: 'tesseract', language: 'eng')
config = Xberg::ExtractionConfig.new(ocr: ocr_config)input = Xberg::ExtractInput.new(uri: 'scanned.pdf')result = Xberg.extract(input, config)puts result.results.first.contentuse xberg::{extract, ExtractionConfig, ExtractInput, OcrConfig};
#[tokio::main]async fn main() -> xberg::Result<()> { let config = ExtractionConfig { ocr: Some(OcrConfig { backend: "tesseract".to_string(), language: vec!["eng".to_string()], ..Default::default() }), ..Default::default() };
let output = extract(ExtractInput::from_uri("scanned.pdf"), &config).await?; println!("{}", output.results[0].content); Ok(())}import Foundationimport Xbergimport RustBridge
let configJson = """{ "ocr": { "backend": "tesseract", "language": "eng" }}"""
let config = try extractionConfigFromJson(configJson)let input = try extractInputFromJson(#"{"kind":"uri","uri":"scanned.pdf"}"#)let resultOutput = try await extract(input: input, config: config)let result = resultOutput.results().get(index: 0)!
print(result.content().toString())alias Xberg.ExtractionConfig
config = %ExtractionConfig{ ocr: %{"enabled" => true, "backend" => "tesseract"}}
{:ok, output} = Xberg.extract(input: %Xberg.ExtractInput{kind: :uri, uri: "scanned_document.pdf"}, config: config)
result = List.first(output.results)content = result.contentIO.puts("OCR Extracted content:")IO.puts(content)IO.puts("Metadata: #{inspect(result.metadata)}")import { ExtractInputKind, extract } from "@xberg-io/xberg";
const config = { ocr: { backend: "tesseract", language: ["eng"], },};
const output = await extract({ kind: ExtractInputKind.Uri, uri: "scanned.pdf" }, config);console.log(output.results?.[0]?.content);import init, { extract } from "@xberg-io/xberg-wasm";
await init();
const fileInput = document.getElementById("file") as HTMLInputElement;const file = fileInput.files?.[0];
if (file) { const bytes = new Uint8Array(await file.arrayBuffer()); const result = await extract( { kind: "bytes", bytes, mimeType: file.type }, { ocr: { enabled: true, backend: "tesseract", language: ["eng"], }, }, ); console.log(result.results[0].content);}import init, { extract } from "@xberg-io/xberg-wasm";
// Outside the browser the default `fetch`-based init cannot read a `file://`// URL: pass the `xberg_wasm_bg.wasm` bytes yourself, either as// `init({ module_or_path: bytes })` or via the synchronous `initSync({ module: bytes })`.await init();
const result = await extract( { kind: "uri", uri: "./scanned_document.png" }, { ocr: { enabled: true, backend: "tesseract", language: ["eng"], }, },);console.log(result.results[0].content);const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { var gpa: std.heap.DebugAllocator(.{}) = .init; defer _ = gpa.deinit(); const allocator = gpa.allocator();
const config_json = \\{ \\ "ocr": { \\ "backend": "tesseract", \\ "language": "eng" \\ } \\} ;
const input_json = "{\"kind\":\"uri\",\"uri\":\"scanned.pdf\"}"; const output_json = try xberg.extract(input_json, config_json); defer std.heap.c_allocator.free(output_json);
const owned = try allocator.dupe(u8, output_json); defer allocator.free(owned);
std.debug.print("{s}\n", .{owned});}xberg extract scanned.pdf --ocr trueProcess Multiple Inputs
Section titled “Process Multiple Inputs”Pass a list of document URIs to extract_batch. Use extract_batch_bytes for in-memory data;
ExtractInput variants can combine URI and byte inputs when a binding exposes the unified API.
extract_batch over URI inputs
import asynciofrom xberg import extract_batch
async def main() -> None: inputs = [{"kind": "uri", "uri": "https://example.com/pdf/fake_memo.pdf"}, {"kind": "uri", "uri": "https://example.com/text/fake_text.txt"}] result = await extract_batch(inputs) for result in result.results: print(result.content)
asyncio.run(main())extract_batch over URI inputs
import { ExtractInput, ExtractInputKind, extractBatch } from "@xberg-io/xberg";async function main() { const result = await extractBatch([{ kind: ExtractInputKind.Uri, uri: "https://example.com/pdf/fake_memo.pdf" } as ExtractInput, { kind: ExtractInputKind.Uri, uri: "https://example.com/text/fake_text.txt" } as ExtractInput]); for (const item of result.results ?? []) { console.log(item.content); }}
void main();extract_batch over URI inputs
import { WasmExtractInput, WasmExtractInputKind, extractBatch } from "@xberg-io/xberg-wasm";async function main() { const result = await extractBatch([(() => { const _u0 = WasmExtractInput.default(); _u0.kind = WasmExtractInputKind.Uri; _u0.uri = "https://example.com/pdf/fake_memo.pdf"; return _u0; })(), (() => { const _u0 = WasmExtractInput.default(); _u0.kind = WasmExtractInputKind.Uri; _u0.uri = "https://example.com/text/fake_text.txt"; return _u0; })()], undefined); for (const item of result.results) { console.log(item.content); }}
void main();extract_batch over URI inputs
use xberg::extract_batch;use xberg::ExtractInput;
#[tokio::main]async fn main() { let inputs_json: serde_json::Value = serde_json::from_str(r#"[{"kind":"uri","uri":"https://example.com/pdf/fake_memo.pdf"},{"kind":"uri","uri":"https://example.com/text/fake_text.txt"}]"#).unwrap(); let inputs = serde_json::from_value::<Vec<ExtractInput>>(inputs_json).unwrap(); let config = Default::default(); let result = extract_batch(inputs, &config).await.expect("call failed"); for result in result.results.iter() { println!("{}", result.content); }}extract_batch over URI inputs
package main
import ( "encoding/json" "fmt" xberg "github.com/xberg-io/xberg/packages/go")
func main() { var inputs []xberg.ExtractInput if err := json.Unmarshal([]byte(`[{"kind":"uri","uri":"https://example.com/pdf/fake_memo.pdf"},{"kind":"uri","uri":"https://example.com/text/fake_text.txt"}]`), &inputs); err != nil { panic(fmt.Sprintf("config parse failed: %v", err)) } config := xberg.ExtractionConfig{} result, err := xberg.ExtractBatch(inputs, config) if err != nil { panic(err) } for _, result := range result.Results { fmt.Printf("%v\n", result.Content) }}extract_batch over URI inputs
import io.xberg.*;
public final class Example { public static void main(String[] args) throws Exception { var result = Xberg.extractBatch(java.util.Arrays.asList(JsonUtil.fromJson("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", ExtractInput.class), JsonUtil.fromJson("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/fake_text.txt\"}", ExtractInput.class)), ExtractionConfig.builder().build()); for (var item : result.results()) { System.out.println(item.content()); } }}extract_batch over URI inputs
import io.xberg.*import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
fun main() = kotlinx.coroutines.runBlocking { val mapper = jacksonObjectMapper().setPropertyNamingStrategy(com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE) val configDefault = mapper.readValue("{\"url\":{\"crawl\":{\"ssrf\":{}}}}", ExtractionConfig::class.java) val result = Xberg.extractBatch(listOf(mapper.readValue("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", ExtractInput::class.java), mapper.readValue("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/fake_text.txt\"}", ExtractInput::class.java)), configDefault) for (result in result.results) { println(result.content) }}extract_batch over URI inputs
using System;using System.Text.Json;using Xberg;
var ConfigOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };var result = await XbergConverter.ExtractBatchAsync(new List<ExtractInput>() { JsonSerializer.Deserialize<ExtractInput>("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", ConfigOptions)!, JsonSerializer.Deserialize<ExtractInput>("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/fake_text.txt\"}", ConfigOptions)! }, new ExtractionConfig());foreach (var resultItem in result.Results){ Console.WriteLine(resultItem.Content);}extract_batch over URI inputs
import Xberg
let _item_inputsArray_0 = try Xberg.extractInputFromJson("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}")let _item_inputsArray_1 = try Xberg.extractInputFromJson("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/fake_text.txt\"}")let inputsArray = [_item_inputsArray_0, _item_inputsArray_1]let configObj = try Xberg.extractionConfigFromJson("{}")let result = try await Xberg.extractBatch(inputs: inputsArray, config: configObj)for result in result.results() { print(result.content())}extract_batch over URI inputs
require "xberg"result = Xberg.extract_batch([{ 'kind' => 'uri', 'uri' => 'https://example.com/pdf/fake_memo.pdf' }, { 'kind' => 'uri', 'uri' => 'https://example.com/text/fake_text.txt' }])result.results.each do |result| puts result.contentendextract_batch over URI inputs
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Xberg\Xberg;use Xberg\ExtractInput;use Xberg\ExtractionConfig;$result = Xberg::extractBatch([ExtractInput::from_json('{"kind":"uri","uri":"https://example.com/pdf/fake_memo.pdf"}'), ExtractInput::from_json('{"kind":"uri","uri":"https://example.com/text/fake_text.txt"}')], \Xberg\ExtractionConfig::from_json('{}'));foreach ($result->getResults() as $result) { echo $result->getContent(), PHP_EOL;}extract_batch over URI inputs
result = Xberg.extract_batch_async([%{"kind" => "uri", "uri" => "https://example.com/pdf/fake_memo.pdf"}, %{"kind" => "uri", "uri" => "https://example.com/text/fake_text.txt"}])Enum.each(result.results, fn result -> IO.puts(result.content)end)extract_batch over URI inputs
import 'dart:convert';import 'dart:io';import 'package:xberg/xberg.dart';import 'package:xberg/src/xberg_bridge_generated/frb_generated.dart' show RustLib;Future<void> main() async { await RustLib.init(); try { final inputs = await Future.wait((jsonDecode(r'[{"kind":"uri","uri":"https://example.com/pdf/fake_memo.pdf"},{"kind":"uri","uri":"https://example.com/text/fake_text.txt"}]') as List<dynamic>).map((element) => createExtractInputFromJson(json: jsonEncode(element)))); final result = await XbergBridge.extractBatch(inputs); for (final result in result.results) { stdout.writeln(result.content); } } finally { RustLib.dispose(); }}extract_batch over URI inputs
const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { const _result_json = try xberg.extract_batch("[{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"},{\"kind\":\"uri\",\"uri\":\"https://example.com/text/fake_text.txt\"}]", "{}"); defer std.heap.c_allocator.free(_result_json); std.debug.print("{s}\n", .{_result_json});
}extract_batch over URI inputs
#include <assert.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "xberg.h"
int main(void) { XBERGAlefHandle result = xberg_extract_batch("[{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"},{\"kind\":\"uri\",\"uri\":\"https://example.com/text/fake_text.txt\"}]", 0); xberg_extraction_result_free(result); return EXIT_SUCCESS;}For command-line batches:
# Process multiple filesxberg extract doc1.pdf doc2.docx doc3.pptx
# Use glob patternsxberg extract documents/**/*.pdfRead Document Metadata
Section titled “Read Document Metadata”Every ExtractionResult contains document metadata in results. Each
ExtractedDocument includes format-specific metadata: page count for PDFs, sheet
names for Excel, dimensions for images:
#include "xberg.h"#include <stdio.h>
int main(void) { /* A config handle is required — zero is rejected as an invalid handle. */ XBERGAlefHandle config = xberg_extraction_config_from_json("{}"); if (config == 0) { fprintf(stderr, "config init failed (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); return 1; }
XBERGAlefHandle input = xberg_extract_input_from_uri("document.pdf"); if (input == 0) { fprintf(stderr, "Failed to create input (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); xberg_extraction_config_free(config); return 1; }
XBERGAlefHandle result = xberg_extract(input, config); if (result == 0) { fprintf(stderr, "extraction failed (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); xberg_extract_input_free(input); xberg_extraction_config_free(config); return 1; }
char *results_json = xberg_extraction_result_results(result); if (results_json) { printf("Results: %s\n", results_json); } xberg_free_string(results_json);
char *full_json = xberg_extraction_result_to_json(result); if (full_json) { printf("Full result: %s\n", full_json); } xberg_free_string(full_json);
xberg_extract_input_free(input); xberg_extraction_result_free(result); xberg_extraction_config_free(config); return 0;}using Xberg;
var config = new ExtractionConfig{ PdfOptions = new PdfConfig { ExtractMetadata = true }};
var result = (await XbergConverter.ExtractAsync(ExtractInput.FromUri("document.pdf"), config)).Results[0];
if (result.Metadata?.Format is FormatMetadata.Pdf pdfFormat){ var pdfMeta = pdfFormat.Value; Console.WriteLine($"Pages: {pdfMeta.PageCount}"); Console.WriteLine($"Author: {string.Join(", ", result.Metadata.Authors ?? new List<string>())}"); Console.WriteLine($"Title: {result.Metadata.Title}");}
var htmlResult = (await XbergConverter.ExtractAsync(ExtractInput.FromUri("page.html"), config)).Results[0];if (htmlResult.Metadata?.Format is FormatMetadata.Html htmlFormat){ var htmlMeta = htmlFormat.Value; Console.WriteLine($"Title: {htmlMeta.Title}"); Console.WriteLine($"Description: {htmlMeta.Description}");
// Access keywords as array if (htmlMeta.Keywords != null && htmlMeta.Keywords.Count > 0) { Console.WriteLine($"Keywords: {string.Join(", ", htmlMeta.Keywords)}"); }
// Access canonical URL (renamed from canonical) if (htmlMeta.CanonicalUrl != null) { Console.WriteLine($"Canonical URL: {htmlMeta.CanonicalUrl}"); }
// Access Open Graph fields from dictionary if (htmlMeta.OpenGraph != null && htmlMeta.OpenGraph.Count > 0) { if (htmlMeta.OpenGraph.ContainsKey("image")) Console.WriteLine($"Open Graph Image: {htmlMeta.OpenGraph["image"]}"); if (htmlMeta.OpenGraph.ContainsKey("title")) Console.WriteLine($"Open Graph Title: {htmlMeta.OpenGraph["title"]}"); if (htmlMeta.OpenGraph.ContainsKey("type")) Console.WriteLine($"Open Graph Type: {htmlMeta.OpenGraph["type"]}"); }
// Access Twitter Card fields from dictionary if (htmlMeta.TwitterCard != null && htmlMeta.TwitterCard.Count > 0) { if (htmlMeta.TwitterCard.ContainsKey("card")) Console.WriteLine($"Twitter Card Type: {htmlMeta.TwitterCard["card"]}"); if (htmlMeta.TwitterCard.ContainsKey("creator")) Console.WriteLine($"Twitter Creator: {htmlMeta.TwitterCard["creator"]}"); }
// Access new fields if (htmlMeta.Language != null) Console.WriteLine($"Language: {htmlMeta.Language}");
if (htmlMeta.TextDirection != null) Console.WriteLine($"Text Direction: {htmlMeta.TextDirection}");
// Access headers if (htmlMeta.Headers != null && htmlMeta.Headers.Count > 0) Console.WriteLine($"Headers: {string.Join(", ", htmlMeta.Headers.Select(h => h.Text))}");
// Access links if (htmlMeta.Links != null && htmlMeta.Links.Count > 0) { foreach (var link in htmlMeta.Links) Console.WriteLine($"Link: {link.Href} ({link.Text})"); }
// Access images if (htmlMeta.Images != null && htmlMeta.Images.Count > 0) Console.WriteLine($"Images: {string.Join(", ", htmlMeta.Images.Select(i => i.Src))}");
// Access structured data if (htmlMeta.StructuredData != null && htmlMeta.StructuredData.Count > 0) Console.WriteLine($"Structured Data items: {htmlMeta.StructuredData.Count}");}import 'package:xberg/xberg.dart';
Future<void> main() async { final config = await createExtractionConfigFromJson(json: '{}'); final result = await XbergBridge.extract( const ExtractInput(kind: ExtractInputKind.uri, uri: 'document.pdf'), config: config, );
final metadata = result.results.first.metadata;
if (metadata.title != null) { print('Title: ${metadata.title}'); } if (metadata.subject != null) { print('Subject: ${metadata.subject}'); } if (metadata.authors != null) { print('Authors: ${metadata.authors!.join(', ')}'); } if (metadata.keywords != null) { print('Keywords: ${metadata.keywords!.join(', ')}'); } if (metadata.language != null) { print('Language: ${metadata.language}'); } if (metadata.createdAt != null) { print('Created: ${metadata.createdAt}'); } if (metadata.modifiedAt != null) { print('Modified: ${metadata.modifiedAt}'); } if (metadata.extractionDurationMs != null) { print('Extraction took: ${metadata.extractionDurationMs} ms'); }
for (final entry in metadata.additional.entries) { print('Additional[${entry.key}]: ${entry.value}'); }}package main
import ( "fmt" "log" "strings"
"github.com/xberg-io/xberg/packages/go")
func main() { input := xberg.ExtractInputFromURI("document.pdf") result, err := xberg.Extract(*input, xberg.ExtractionConfig{}) if err != nil { log.Fatalf("extract pdf: %v", err) }
// Access PDF metadata if format := result.Results[0].Metadata.Format; format != nil && format.Pdf != nil { pdf := format.Pdf if pdf.PageCount != nil { fmt.Printf("Pages: %d\n", *pdf.PageCount) } if len(result.Results[0].Metadata.Authors) > 0 { fmt.Printf("Authors: %s\n", strings.Join(result.Results[0].Metadata.Authors, ", ")) } if result.Results[0].Metadata.Title != nil { fmt.Printf("Title: %s\n", *result.Results[0].Metadata.Title) } }
// Access HTML metadata htmlInput := xberg.ExtractInputFromURI("page.html") htmlResult, err := xberg.Extract(*htmlInput, xberg.ExtractionConfig{}) if err != nil { log.Fatalf("extract html: %v", err) } if format := htmlResult.Results[0].Metadata.Format; format != nil && format.HTML != nil { html := format.HTML if html.Title != nil { fmt.Printf("Title: %s\n", *html.Title) } if html.Description != nil { fmt.Printf("Description: %s\n", *html.Description) }
// Access keywords as array if len(html.Keywords) > 0 { fmt.Printf("Keywords: %s\n", strings.Join(html.Keywords, ", ")) }
// Access canonical URL (renamed from canonical) if html.CanonicalURL != nil { fmt.Printf("Canonical URL: %s\n", *html.CanonicalURL) }
// Access Open Graph fields from map if len(html.OpenGraph) > 0 { if image, ok := html.OpenGraph["image"]; ok { fmt.Printf("Open Graph Image: %s\n", image) } if ogTitle, ok := html.OpenGraph["title"]; ok { fmt.Printf("Open Graph Title: %s\n", ogTitle) } if ogType, ok := html.OpenGraph["type"]; ok { fmt.Printf("Open Graph Type: %s\n", ogType) } }
// Access Twitter Card fields from map if len(html.TwitterCard) > 0 { if card, ok := html.TwitterCard["card"]; ok { fmt.Printf("Twitter Card Type: %s\n", card) } if creator, ok := html.TwitterCard["creator"]; ok { fmt.Printf("Twitter Creator: %s\n", creator) } }
// Access new fields if html.Language != nil { fmt.Printf("Language: %s\n", *html.Language) }
if html.TextDirection != nil { fmt.Printf("Text Direction: %s\n", *html.TextDirection) }
// Access headers if len(html.Headers) > 0 { headers := make([]string, len(html.Headers)) for i, h := range html.Headers { headers[i] = h.Text } fmt.Printf("Headers: %s\n", strings.Join(headers, ", ")) }
// Access links if len(html.Links) > 0 { for _, link := range html.Links { fmt.Printf("Link: %s (%s)\n", link.Href, link.Text) } }
// Access images if len(html.Images) > 0 { for _, image := range html.Images { fmt.Printf("Image: %s\n", image.Src) } }
// Access structured data if len(html.StructuredData) > 0 { fmt.Printf("Structured data items: %d\n", len(html.StructuredData)) } }}import io.xberg.Xberg;import io.xberg.ExtractInputKind;import io.xberg.ExtractedDocument;import io.xberg.Metadata;import io.xberg.XbergRsException;import java.util.Map;import java.util.List;
public class Main { public static void main(String[] args) { try { var resultOutput = Xberg.extract( io.xberg.ExtractInput.builder() .withKind(io.xberg.ExtractInputKind.URI) .withUri("document.pdf") .build(), io.xberg.ExtractionConfig.builder().build() ); ExtractedDocument result = resultOutput.results().get(0); // Metadata is flat — format-specific fields are at the top level Metadata metadata = result.metadata(); if (metadata.title() != null) { System.out.println("Title: " + metadata.title()); } if (metadata.authors() != null) { System.out.println("Authors: " + String.join(", ", metadata.authors())); } // Format-specific fields are in the additional map Map<String, Object> extra = metadata.additional(); if (extra != null && extra.get("page_count") != null) { System.out.println("Pages: " + extra.get("page_count")); } // Access HTML metadata var htmlResultOutput = Xberg.extract( io.xberg.ExtractInput.builder() .withKind(io.xberg.ExtractInputKind.URI) .withUri("page.html") .build(), io.xberg.ExtractionConfig.builder().build() ); ExtractedDocument htmlResult = htmlResultOutput.results().get(0); Metadata htmlMeta = htmlResult.metadata(); if (htmlMeta.title() != null) { System.out.println("Title: " + htmlMeta.title()); } Map<String, Object> htmlExtra = htmlMeta.additional(); String description = htmlExtra != null ? (String) htmlExtra.get("description") : null; if (description != null) { System.out.println("Description: " + description); } // Access keywords as array if (htmlMeta.keywords() != null) { System.out.println("Keywords: " + htmlMeta.keywords()); } // Access canonical URL (renamed from canonical) String canonicalUrl = htmlExtra != null ? (String) htmlExtra.get("canonical_url") : null; if (canonicalUrl != null) { System.out.println("Canonical URL: " + canonicalUrl); } // Access Open Graph fields from map @SuppressWarnings("unchecked") Map<String, String> openGraph = htmlExtra != null ? (Map<String, String>) htmlExtra.get("open_graph") : null; if (openGraph != null) { System.out.println("Open Graph Image: " + openGraph.get("image")); System.out.println("Open Graph Title: " + openGraph.get("title")); System.out.println("Open Graph Type: " + openGraph.get("type")); } // Access Twitter Card fields from map @SuppressWarnings("unchecked") Map<String, String> twitterCard = htmlExtra != null ? (Map<String, String>) htmlExtra.get("twitter_card") : null; if (twitterCard != null) { System.out.println("Twitter Card Type: " + twitterCard.get("card")); System.out.println("Twitter Creator: " + twitterCard.get("creator")); } // Access new fields if (htmlMeta.language() != null) { System.out.println("Language: " + htmlMeta.language()); } String textDirection = htmlExtra != null ? (String) htmlExtra.get("text_direction") : null; if (textDirection != null) { System.out.println("Text Direction: " + textDirection); } // Access headers @SuppressWarnings("unchecked") List<Map<String, Object>> headers = htmlExtra != null ? (List<Map<String, Object>>) htmlExtra.get("headers") : null; if (headers != null) { headers.stream() .map(h -> h.get("text")) .forEach(text -> System.out.print(text + ", ")); System.out.println(); } // Access links @SuppressWarnings("unchecked") List<Map<String, Object>> links = htmlExtra != null ? (List<Map<String, Object>>) htmlExtra.get("links") : null; if (links != null) { for (Map<String, Object> link : links) { System.out.println("Link: " + link.get("href") + " (" + link.get("text") + ")"); } } // Access images @SuppressWarnings("unchecked") List<Map<String, Object>> images = htmlExtra != null ? (List<Map<String, Object>>) htmlExtra.get("images") : null; if (images != null) { for (Map<String, Object> image : images) { System.out.println("Image: " + image.get("src")); } } // Access structured data @SuppressWarnings("unchecked") List<Map<String, Object>> structuredData = htmlExtra != null ? (List<Map<String, Object>>) htmlExtra.get("structured_data") : null; if (structuredData != null) { System.out.println("Structured data items: " + structuredData.size()); } } catch (XbergRsException e) { System.err.println("Extraction failed: " + e.getMessage()); } }}import io.xberg.*
private const val DEFAULT_MAX_ARCHIVE_DEPTH = 3Lprivate const val DEFAULT_EXTRACTION_TIMEOUT_SECS = 600Lprivate const val DEFAULT_MAX_EMBEDDED_FILE_BYTES = 50L * 1024L * 1024L
fun main() { val config = ExtractionConfig( extractionTimeoutSecs = DEFAULT_EXTRACTION_TIMEOUT_SECS, maxEmbeddedFileBytes = DEFAULT_MAX_EMBEDDED_FILE_BYTES, url = UrlExtractionConfig(crawl = CrawlConfig(ssrf = SsrfPolicy())), maxArchiveDepth = DEFAULT_MAX_ARCHIVE_DEPTH, ) val resultOutput = Xberg.extract( ExtractInput(kind = ExtractInputKind.URI, uri = "document.pdf"), config, ) val result = resultOutput.results.first()
val metadata = result.metadata metadata.title?.let { println("Title: $it") } metadata.authors?.let { println("Authors: ${it.joinToString(", ")}") }
when (val format = metadata.format) { is FormatMetadata.Pdf -> { format.metadata.pageCount?.let { println("Pages: $it") } format.metadata.producer?.let { println("Producer: $it") } format.metadata.pdfVersion?.let { println("PDF Version: $it") } } else -> Unit }
val htmlResultOutput = Xberg.extract( ExtractInput(kind = ExtractInputKind.URI, uri = "page.html"), config, ) val htmlResult = htmlResultOutput.results.first() when (val format = htmlResult.metadata.format) { is FormatMetadata.Html -> { val html = format.metadata html.title?.let { println("Title: $it") } html.description?.let { println("Description: $it") } html.canonicalUrl?.let { println("Canonical URL: $it") } html.language?.let { println("Language: $it") } println("Keywords: ${html.keywords}") html.openGraph["image"]?.let { println("Open Graph Image: $it") } html.openGraph["title"]?.let { println("Open Graph Title: $it") } html.twitterCard["card"]?.let { println("Twitter Card Type: $it") } for (header in html.headers) { println("Header (level ${header.level}): ${header.text}") } for (link in html.links) { println("Link: ${link.href} (${link.text})") } for (image in html.images) { println("Image: ${image.src}") } if (html.structuredData.isNotEmpty()) { println("Structured data items: ${html.structuredData.size}") } } else -> Unit }}import asynciofrom xberg import ExtractInput, extract, ExtractionConfig
async def main() -> None: result = await extract(ExtractInput(uri="document.pdf"), ExtractionConfig())
# Common fields live directly on Metadata metadata = result.results[0].metadata pdf_metadata = metadata.format.pdf if metadata.format else None if pdf_metadata and pdf_metadata.page_count: print(f"Pages: {pdf_metadata.page_count}") if metadata.title: print(f"Title: {metadata.title}") if metadata.authors: print(f"Authors: {', '.join(metadata.authors)}")
html_result = await extract(ExtractInput(uri="page.html"), ExtractionConfig()) html_metadata = html_result.results[0].metadata html_format = html_metadata.format.html if html_metadata.format else None if html_format: if html_format.title: print(f"Title: {html_format.title}") if html_format.description: print(f"Description: {html_format.description}")
# Access keywords as array if html_format.keywords: print(f"Keywords: {', '.join(html_format.keywords)}")
# Access canonical URL if html_format.canonical_url: print(f"Canonical URL: {html_format.canonical_url}")
# Access Open Graph fields from map if html_format.open_graph: if "image" in html_format.open_graph: print(f"Open Graph Image: {html_format.open_graph['image']}") if "title" in html_format.open_graph: print(f"Open Graph Title: {html_format.open_graph['title']}") if "type" in html_format.open_graph: print(f"Open Graph Type: {html_format.open_graph['type']}")
# Access Twitter Card fields from map if html_format.twitter_card: if "card" in html_format.twitter_card: print(f"Twitter Card Type: {html_format.twitter_card['card']}") if "creator" in html_format.twitter_card: print(f"Twitter Creator: {html_format.twitter_card['creator']}")
if html_format.language: print(f"Language: {html_format.language}")
if html_format.text_direction: print(f"Text Direction: {html_format.text_direction}")
# Access headers if html_format.headers: print(f"Headers: {', '.join(h.text for h in html_format.headers)}")
# Access links if html_format.links: for link in html_format.links: print(f"Link: {link.href} ({link.text})")
# Access images if html_format.images: for image in html_format.images: print(f"Image: {image}")
# Access structured data if html_format.structured_data: print(f"Structured data items: {len(html_format.structured_data)}")
asyncio.run(main())require 'xberg'
input = Xberg::ExtractInput.new(uri: 'document.pdf')config = Xberg::ExtractionConfig.newresult = Xberg.extract(input, config)
# Metadata is flat — format-specific fields are at the top levelmetadata = result.results.first.metadataif metadata['page_count'] puts "Pages: #{metadata['page_count']}"endif metadata['title'] puts "Title: #{metadata['title']}"endif metadata['authors'] puts "Authors: #{metadata['authors'].join(', ')}"end
# Access HTML metadatahtml_input = Xberg::ExtractInput.new(uri: 'page.html')html_result = Xberg.extract(html_input, Xberg::ExtractionConfig.new)metadata = html_result.results.first.metadataif metadata['title'] puts "Title: #{metadata['title']}"endif metadata['description'] puts "Description: #{metadata['description']}"end
# Access keywords as arrayif metadata['keywords'] puts "Keywords: #{metadata['keywords'].join(', ')}"end
# Access canonical URL (renamed from canonical)puts "Canonical URL: #{metadata['canonical_url']}" if metadata['canonical_url']
# Access Open Graph fields from mapopen_graph = metadata['open_graph'] || {}puts "Open Graph Image: #{open_graph['image']}" if open_graph['image']puts "Open Graph Title: #{open_graph['title']}" if open_graph['title']puts "Open Graph Type: #{open_graph['type']}" if open_graph['type']
# Access Twitter Card fields from maptwitter_card = metadata['twitter_card'] || {}puts "Twitter Card Type: #{twitter_card['card']}" if twitter_card['card']puts "Twitter Creator: #{twitter_card['creator']}" if twitter_card['creator']
# Access new fieldsputs "Language: #{metadata['language']}" if metadata['language']puts "Text Direction: #{metadata['text_direction']}" if metadata['text_direction']
# Access headersif metadata['headers'] puts "Headers: #{metadata['headers'].map { |h| h['text'] }.join(', ')}"end
# Access linksif metadata['links'] metadata['links'].each do |link| puts "Link: #{link['href']} (#{link['text']})" endend
# Access imagesif metadata['images'] metadata['images'].each do |image| puts "Image: #{image['src']}" endend
# Access structured dataif metadata['structured_data'] puts "Structured data items: #{metadata['structured_data'].length}"enduse xberg::{extract, ExtractionConfig, ExtractInput, FormatMetadata};
#[tokio::main]async fn main() -> xberg::Result<()> { let output = extract(ExtractInput::from_uri("document.pdf"), &ExtractionConfig::default()).await?; let result = &output.results[0];
// Common bibliographic fields live on `Metadata` directly. if let Some(title) = &result.metadata.title { println!("Title: {}", title); } if let Some(authors) = &result.metadata.authors { println!("Author: {}", authors.join(", ")); }
// Format-specific fields are behind the `FormatMetadata` discriminated union. if let Some(FormatMetadata::Pdf(pdf_meta)) = &result.metadata.format { if let Some(pages) = pdf_meta.page_count { println!("Pages: {}", pages); } }
let html_output = extract(ExtractInput::from_uri("page.html"), &ExtractionConfig::default()).await?; let html_result = &html_output.results[0]; if let Some(FormatMetadata::Html(html_meta)) = &html_result.metadata.format { if let Some(title) = &html_meta.title { println!("Title: {}", title); } if let Some(desc) = &html_meta.description { println!("Description: {}", desc); }
// Access keywords array println!("Keywords: {:?}", html_meta.keywords);
// Access canonical URL (renamed from canonical) if let Some(canonical) = &html_meta.canonical_url { println!("Canonical URL: {}", canonical); }
// Access Open Graph fields as a map if let Some(og_image) = html_meta.open_graph.get("image") { println!("Open Graph Image: {}", og_image); } if let Some(og_title) = html_meta.open_graph.get("title") { println!("Open Graph Title: {}", og_title); }
// Access Twitter Card fields as a map if let Some(twitter_card) = html_meta.twitter_card.get("card") { println!("Twitter Card Type: {}", twitter_card); }
// Access new fields if let Some(lang) = &html_meta.language { println!("Language: {}", lang); }
// Access headers if !html_meta.headers.is_empty() { for header in &html_meta.headers { println!("Header (level {}): {}", header.level, header.text); } }
// Access links if !html_meta.links.is_empty() { for link in &html_meta.links { println!("Link: {} ({})", link.href, link.text); } }
// Access images if !html_meta.images.is_empty() { for image in &html_meta.images { println!("Image: {}", image.src); } }
// Access structured data if !html_meta.structured_data.is_empty() { println!("Structured data items: {}", html_meta.structured_data.len()); } } Ok(())}import Foundationimport Xbergimport RustBridge
let config = try extractionConfigFromJson("{}")let input = try extractInputFromJson(#"{"kind":"uri","uri":"document.pdf"}"#)let resultOutput = try await extract(input: input, config: config)let result = resultOutput.results().get(index: 0)!
let metadata = result.metadata()
if let title = metadata.title() { print("Title: \(title.toString())")}if let subject = metadata.subject() { print("Subject: \(subject.toString())")}if let language = metadata.language() { print("Language: \(language.toString())")}if let createdAt = metadata.createdAt() { print("Created at: \(createdAt.toString())")}if let modifiedAt = metadata.modifiedAt() { print("Modified at: \(modifiedAt.toString())")}if let createdBy = metadata.createdBy() { print("Created by: \(createdBy.toString())")}// List-valued metadata crosses the bridge as a JSON array string.print("Authors: \(metadata.authors().toString())")print("Keywords: \(metadata.keywords().toString())")if let duration = metadata.extractionDurationMs() { print("Extraction duration (ms): \(duration)")}if let pages = metadata.pages() { print("Page count: \(pages.totalCount())")}{:ok, output} = Xberg.extract(input: %Xberg.ExtractInput{kind: :uri, uri: "document.pdf"}, config: nil)result = List.first(output.results)# Metadata is flat — format-specific fields are at the top levelmetadata = result.metadataIO.puts("MIME type: #{result.mime_type}")IO.puts("All metadata keys: #{inspect(Map.keys(metadata))}")
# Access PDF metadata directly from the flat mappage_count = metadata["page_count"]if page_count, do: IO.puts("Page count: #{page_count}")
authors = metadata["authors"] || []if authors != [], do: IO.puts("Authors: #{Enum.join(authors, ", ")}")
title = metadata["title"]if title, do: IO.puts("Title: #{title}")
# Access HTML metadata directly from the flat map{:ok, html_output} = Xberg.extract(input: %Xberg.ExtractInput{kind: :uri, uri: "page.html"}, config: nil)html_result = List.first(html_output.results)html_meta = html_result.metadata
keywords = html_meta["keywords"] || []if keywords != [], do: IO.puts("Keywords: #{Enum.join(keywords, ", ")}")
description = html_meta["description"]if description, do: IO.puts("Description: #{description}")import { ExtractInputKind, extract } from "@xberg-io/xberg";
const output = await extract({ kind: ExtractInputKind.Uri, uri: "document.pdf",});const result = output.results?.[0];console.log(`Metadata: ${JSON.stringify(result?.metadata)}`);if (result?.metadata?.pages?.totalCount) { console.log(`Pages: ${result.metadata.pages.totalCount}`);}
const htmlOutput = await extract({ kind: ExtractInputKind.Uri, uri: "page.html",});const htmlResult = htmlOutput.results?.[0];console.log(`HTML Metadata: ${JSON.stringify(htmlResult?.metadata)}`);
const htmlFormat = htmlResult?.metadata?.format;const htmlMeta = htmlFormat?.formatType === "html" ? htmlFormat : undefined;if (htmlMeta?.title) { console.log(`Title: ${htmlMeta.title}`);}
// Access keywords as arrayif (htmlMeta?.keywords && htmlMeta.keywords.length > 0) { console.log(`Keywords: ${htmlMeta.keywords.join(", ")}`);}
// Access canonical URL (renamed from canonical)if (htmlMeta?.canonicalUrl) { console.log(`Canonical URL: ${htmlMeta.canonicalUrl}`);}
// Access Open Graph fields from mapif (htmlMeta?.openGraph) { if (htmlMeta.openGraph["image"]) { console.log(`Open Graph Image: ${htmlMeta.openGraph["image"]}`); } if (htmlMeta.openGraph["title"]) { console.log(`Open Graph Title: ${htmlMeta.openGraph["title"]}`); } if (htmlMeta.openGraph["type"]) { console.log(`Open Graph Type: ${htmlMeta.openGraph["type"]}`); }}
// Access Twitter Card fields from mapif (htmlMeta?.twitterCard) { if (htmlMeta.twitterCard["card"]) { console.log(`Twitter Card Type: ${htmlMeta.twitterCard["card"]}`); } if (htmlMeta.twitterCard["creator"]) { console.log(`Twitter Creator: ${htmlMeta.twitterCard["creator"]}`); }}
// Access new fieldsif (htmlMeta?.language) { console.log(`Language: ${htmlMeta.language}`);}
if (htmlMeta?.textDirection) { console.log(`Text Direction: ${htmlMeta.textDirection}`);}
// Access headersif (htmlMeta?.headers && htmlMeta.headers.length > 0) { console.log(`Headers: ${htmlMeta.headers.map((h) => h.text).join(", ")}`);}
// Access linksif (htmlMeta?.links && htmlMeta.links.length > 0) { htmlMeta.links.forEach((link) => { console.log(`Link: ${link.href} (${link.text})`); });}
// Access imagesif (htmlMeta?.images && htmlMeta.images.length > 0) { htmlMeta.images.forEach((image) => { console.log(`Image: ${image.src}`); });}
// Access structured dataif (htmlMeta?.structuredData && htmlMeta.structuredData.length > 0) { console.log(`Structured data items: ${htmlMeta.structuredData.length}`);}import init, { extract } from "@xberg-io/xberg-wasm";
await init();
const fileInput = document.getElementById("file") as HTMLInputElement;const file = fileInput.files?.[0];
if (file) { const bytes = new Uint8Array(await file.arrayBuffer()); const result = await extract({ kind: "bytes", bytes, mimeType: file.type || "application/octet-stream" }, undefined); console.log(`Metadata: ${JSON.stringify(result.results[0].metadata)}`);
// Access common metadata fields if (result.results[0].metadata.title) { console.log(`Title: ${result.results[0].metadata.title}`); }
// Access format-specific metadata const metadata = result.results[0].metadata;
// For HTML files if (metadata.format?.format_type === "html") { const htmlMeta = metadata.format; console.log(`HTML Title: ${htmlMeta.title}`); console.log(`Description: ${htmlMeta.description}`);
// Access keywords as array if (htmlMeta.keywords && htmlMeta.keywords.length > 0) { console.log(`Keywords: ${htmlMeta.keywords.join(", ")}`); }
// Access canonical URL if (htmlMeta.canonical_url) { console.log(`Canonical URL: ${htmlMeta.canonical_url}`); }
// Access Open Graph fields if (htmlMeta.open_graph) { if (htmlMeta.open_graph["title"]) { console.log(`OG Title: ${htmlMeta.open_graph["title"]}`); } if (htmlMeta.open_graph["image"]) { console.log(`OG Image: ${htmlMeta.open_graph["image"]}`); } }
// Access Twitter Card fields if (htmlMeta.twitter_card && htmlMeta.twitter_card["card"]) { console.log(`Twitter Card Type: ${htmlMeta.twitter_card["card"]}`); }
// Access headers if (htmlMeta.headers && htmlMeta.headers.length > 0) { console.log(`Headers: ${htmlMeta.headers.map((h: any) => h.text).join(", ")}`); }
// Access links if (htmlMeta.links && htmlMeta.links.length > 0) { htmlMeta.links.forEach((link: any) => { console.log(`Link: ${link.href} (${link.text})`); }); }
// Access images if (htmlMeta.images && htmlMeta.images.length > 0) { htmlMeta.images.forEach((image: any) => { console.log(`Image: ${image.src}`); }); }
// Access structured data if (htmlMeta.structured_data && htmlMeta.structured_data.length > 0) { console.log(`Structured data items: ${htmlMeta.structured_data.length}`); } }
// PDF-specific fields are at the top level of metadata if (metadata.pages) { console.log(`Pages: ${metadata.pages.totalCount}`); } if (metadata.authors && metadata.authors.length > 0) { console.log(`Authors: ${metadata.authors.join(", ")}`); }}const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { var gpa: std.heap.DebugAllocator(.{}) = .init; defer _ = gpa.deinit(); const allocator = gpa.allocator();
const config_json = "{}"; const input_json = "{\"kind\":\"uri\",\"uri\":\"document.pdf\"}"; const output_json = try xberg.extract(input_json, config_json); defer std.heap.c_allocator.free(output_json);
var parsed = try std.json.parseFromSlice(std.json.Value, allocator, output_json, .{}); defer parsed.deinit();
const output = parsed.value; if (output != .object) return;
const results_val = output.object.get("results") orelse return; if (results_val != .array or results_val.array.items.len == 0) return; const root = results_val.array.items[0]; if (root != .object) return;
if (root.object.get("metadata")) |metadata_val| { if (metadata_val != .object) return; const metadata = metadata_val.object;
if (metadata.get("title")) |title_val| { if (title_val == .string) { std.debug.print("Title: {s}\n", .{title_val.string}); } }
if (metadata.get("authors")) |authors_val| { if (authors_val == .array) { for (authors_val.array.items) |author| { if (author == .string) { std.debug.print("Author: {s}\n", .{author.string}); } } } }
if (metadata.get("language")) |language_val| { if (language_val == .string) { std.debug.print("Language: {s}\n", .{language_val.string}); } }
if (metadata.get("created_at")) |created_val| { if (created_val == .string) { std.debug.print("Created: {s}\n", .{created_val.string}); } }
if (metadata.get("pages")) |pages_val| { if (pages_val == .object) { if (pages_val.object.get("total_count")) |total_val| { if (total_val == .integer) { std.debug.print("Pages: {d}\n", .{total_val.integer}); } } } } }}Extract and parse metadata using JSON output:
# Extract with metadata (JSON format includes metadata automatically)xberg extract document.pdf --format json
# Save to file and parse metadataxberg extract document.pdf --format json > result.json
# Print all metadata fieldscat result.json | jq '.metadata'
# Extract HTML metadataxberg extract page.html --format json | jq '.metadata'
# Get specific fieldsxberg extract document.pdf --format json | \ jq '.metadata | {page_count, authors, title}'
# Process multiple filesxberg batch documents/*.pdf --format json > all_metadata.jsonJSON Output Structure:
{ "results": [ { "content": "Extracted text...", "mime_type": "application/pdf", "metadata": { "title": "Document Title", "authors": ["John Doe"], "created_by": "LaTeX with hyperref package", "format_type": "pdf", "page_count": 10 }, "tables": [] } ], "errors": [], "summary": { "inputs": 1, "results": 1, "errors": 0 }}Xberg extracts format-specific metadata for:
- PDF: page count, title, authors (list), creation date, modification date
- HTML: SEO tags, Open Graph, Twitter Card, structured data, headers, links, images
- Excel: sheet count, sheet names
- Email: from, to, CC, BCC, message ID, attachments
- PowerPoint: title, author, description, fonts
- Images: dimensions, format, EXIF data
- Archives: format, file count, file list, sizes
- XML: element count, unique elements
- Text/Markdown: word count, line count, headers, links
See Types Reference for complete metadata reference.
Extract Tables
Section titled “Extract Tables”Tables come back as both structured cells and Markdown. Xberg extracts them from PDFs, spreadsheets, and HTML:
#include "xberg.h"#include <stdio.h>
int main(void) { /* A config handle is required — zero is rejected as an invalid handle. */ XBERGAlefHandle config = xberg_extraction_config_from_json("{}"); if (config == 0) { fprintf(stderr, "config init failed (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); return 1; }
XBERGAlefHandle input = xberg_extract_input_from_uri("spreadsheet.xlsx"); if (input == 0) { fprintf(stderr, "Failed to create input (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); xberg_extraction_config_free(config); return 1; }
XBERGAlefHandle result = xberg_extract(input, config); if (result == 0) { fprintf(stderr, "extraction failed (code %d): %s\n", xberg_last_error_code(), xberg_last_error_context()); xberg_extract_input_free(input); xberg_extraction_config_free(config); return 1; }
char *result_json = xberg_extraction_result_to_json(result); if (result_json) { printf("Extraction result (JSON): %s\n", result_json); } else { printf("No extraction result available\n"); } xberg_free_string(result_json);
xberg_extract_input_free(input); xberg_extraction_result_free(result); xberg_extraction_config_free(config); return 0;}using Xberg;
var result = (await XbergConverter.ExtractAsync(ExtractInput.FromUri("document.pdf"), new ExtractionConfig())).Results[0];
foreach (var table in result.Tables){ Console.WriteLine($"Table with {table.Cells.Count} rows"); Console.WriteLine(table.Markdown);
foreach (var row in table.Cells) { Console.WriteLine(string.Join(" | ", row)); }}import 'package:xberg/xberg.dart';
Future<void> main() async { final config = await createExtractionConfigFromJson(json: '{}'); final result = await XbergBridge.extract( const ExtractInput(kind: ExtractInputKind.uri, uri: 'document.pdf'), config: config, );
for (final table in result.results[0].tables) { print('Table on page ${table.pageNumber} with ${table.cells.length} rows'); print(table.markdown);
for (final row in table.cells) { print(row); }
if (table.boundingBox != null) { print('Bounding box: ${table.boundingBox}'); } }}package main
import ( "fmt" "log"
"github.com/xberg-io/xberg/packages/go")
func main() { input := xberg.ExtractInputFromURI("document.pdf") result, err := xberg.Extract(*input, xberg.ExtractionConfig{}) if err != nil { log.Fatalf("extract failed: %v", err) }
// Iterate over tables for _, table := range result.Results[0].Tables { fmt.Printf("Table with %d rows\n", len(table.Cells)) fmt.Println(table.Markdown) // Markdown representation
// Access cells for _, row := range table.Cells { fmt.Println(row) } }}import io.xberg.Xberg;import io.xberg.ExtractInputKind;import io.xberg.ExtractionResult;import io.xberg.ExtractedDocument;import io.xberg.XbergRsException;import io.xberg.ExtractInput;import io.xberg.ExtractionConfig;import io.xberg.Table;import java.util.List;
public class Main { public static void main(String[] args) { try { ExtractionResult output = Xberg.extract( ExtractInput.builder().withKind(ExtractInputKind.URI).withUri("document.pdf").build(), ExtractionConfig.builder().build() ); ExtractedDocument result = output.results().get(0); for (Table table : result.tables()) { System.out.println("Table with " + table.cells().size() + " rows"); System.out.println(table.markdown()); for (List<String> row : table.cells()) { System.out.println(row); } } } catch (XbergRsException e) { System.err.println("Extraction failed: " + e.getMessage()); } }}import io.xberg.*
private const val DEFAULT_MAX_ARCHIVE_DEPTH = 3Lprivate const val DEFAULT_EXTRACTION_TIMEOUT_SECS = 600Lprivate const val DEFAULT_MAX_EMBEDDED_FILE_BYTES = 50L * 1024L * 1024L
fun main() { val config = ExtractionConfig( extractionTimeoutSecs = DEFAULT_EXTRACTION_TIMEOUT_SECS, maxEmbeddedFileBytes = DEFAULT_MAX_EMBEDDED_FILE_BYTES, url = UrlExtractionConfig(crawl = CrawlConfig(ssrf = SsrfPolicy())), maxArchiveDepth = DEFAULT_MAX_ARCHIVE_DEPTH, ) val resultOutput = Xberg.extract( ExtractInput(kind = ExtractInputKind.URI, uri = "document.pdf"), config, ) val result = resultOutput.results.first()
val tables = result.tables for (table in tables) { println("Table on page ${table.pageNumber} with ${table.cells.size} rows") println(table.markdown)
for (row in table.cells) { println(row) } }}import asynciofrom xberg import ExtractInput, extract, ExtractionConfig
async def main() -> None: result = await extract(ExtractInput(uri="document.pdf"), ExtractionConfig())
for table in result.results[0].tables: row_count: int = len(table.cells) print(f"Table with {row_count} rows") print(table.markdown) for row in table.cells: print(row)
asyncio.run(main())require 'xberg'
input = Xberg::ExtractInput.new(uri: 'document.pdf')config = Xberg::ExtractionConfig.newresult = Xberg.extract(input, config)
# Iterate over tablesresult.results.first.tables.each do |table| puts "Table with #{table['cells'].length} rows" puts table['markdown'] # Markdown representation
# Access cells table['cells'].each do |row| puts row endenduse xberg::{extract, ExtractionConfig, ExtractInput};
#[tokio::main]async fn main() -> xberg::Result<()> { let output = extract(ExtractInput::from_uri("document.pdf"), &ExtractionConfig::default()).await?; let result = &output.results[0];
for table in &result.tables { println!("Table with {} rows", table.cells.len()); println!("{}", table.markdown);
for row in &table.cells { println!("{:?}", row); } } Ok(())}import Foundationimport Xbergimport RustBridge
let config = try extractionConfigFromJson("{}")let input = try extractInputFromJson(#"{"kind":"uri","uri":"document.pdf"}"#)let resultOutput = try await extract(input: input, config: config)let result = resultOutput.results().get(index: 0)!
let tables = result.tables()print("Tables: \(tables.count)")
for (index, table) in tables.enumerated() { print("Table \(index) on page \(table.pageNumber())") print(table.markdown().toString())
if let bbox = table.boundingBox() { print(" Bounding box: \(bbox.x0()), \(bbox.y0()), \(bbox.x1()), \(bbox.y1())") }}{:ok, output} = Xberg.extract(input: %Xberg.ExtractInput{kind: :uri, uri: "document.pdf"}, config: nil)result = List.first(output.results)tables = result.tablesIO.puts("Total tables found: #{length(tables)}")
Enum.with_index(tables, 1) |> Enum.each(fn {table, index} -> IO.puts("\n--- Table #{index} ---")
# Access table cells cells = table["cells"] || [] IO.puts("Rows: #{length(cells)}")
# Access table markdown representation markdown = table["markdown"] IO.puts("Markdown representation:") IO.puts(markdown)end)import { ExtractInputKind, extract } from "@xberg-io/xberg";
const output = await extract({ kind: ExtractInputKind.Uri, uri: "document.pdf",});
const [first] = output.results ?? [];first?.tables?.forEach((table) => { console.log(`Table with ${table.cells?.length ?? 0} rows`); console.log(table.markdown); table.cells?.forEach((row) => console.log(row.join(" | ")));});import init, { extract } from "@xberg-io/xberg-wasm";
await init();
const fileInput = document.getElementById("file") as HTMLInputElement;const file = fileInput.files?.[0];
if (file) { const bytes = new Uint8Array(await file.arrayBuffer()); const result = await extract({ kind: "bytes", bytes, mimeType: file.type || "application/pdf" }, undefined);
result.results[0].tables?.forEach((table) => { console.log(`Table with ${table.cells?.length ?? 0} rows`); if (table.markdown) { console.log(table.markdown); } table.cells?.forEach((row: string[]) => console.log(row.join(" | "))); });}const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { var gpa: std.heap.DebugAllocator(.{}) = .init; defer _ = gpa.deinit(); const allocator = gpa.allocator();
const config_json = "{}"; const input_json = "{\"kind\":\"uri\",\"uri\":\"document.pdf\"}"; const output_json = try xberg.extract(input_json, config_json); defer std.heap.c_allocator.free(output_json);
var parsed = try std.json.parseFromSlice(std.json.Value, allocator, output_json, .{}); defer parsed.deinit();
const output = parsed.value; if (output != .object) return;
const results_val = output.object.get("results") orelse return; if (results_val != .array or results_val.array.items.len == 0) return; const root = results_val.array.items[0]; if (root != .object) return;
const tables_val = root.object.get("tables") orelse return; if (tables_val != .array) return;
for (tables_val.array.items) |table| { if (table != .object) continue;
if (table.object.get("cells")) |cells_val| { if (cells_val == .array) { std.debug.print("Table with {d} rows\n", .{cells_val.array.items.len});
for (cells_val.array.items) |row_val| { if (row_val != .array) continue; std.debug.print(" Row:", .{}); for (row_val.array.items) |cell_val| { if (cell_val == .string) { std.debug.print(" [{s}]", .{cell_val.string}); } } std.debug.print("\n", .{}); } } }
if (table.object.get("markdown")) |markdown_val| { if (markdown_val == .string) { std.debug.print("{s}\n", .{markdown_val.string}); } }
if (table.object.get("page_number")) |page_val| { if (page_val == .integer) { std.debug.print("Page: {d}\n", .{page_val.integer}); } } }}Extract and process tables from documents:
# Extract with JSON format (includes tables when detected)xberg extract document.pdf --format json
# Save tables to JSONxberg extract spreadsheet.xlsx --format json > tables.json
# Extract and parse table markdownxberg extract document.pdf --format json | \ jq '.tables[]? | .markdown'
# Get table cellsxberg extract document.pdf --format json | \ jq '.tables[]? | .cells'
# Batch extract tables from multiple filesxberg batch documents/**/*.pdf --format json > all_tables.jsonJSON Table Structure:
{ "results": [ { "content": "...", "tables": [ { "cells": [ ["Name", "Age", "City"], ["Alice", "30", "New York"], ["Bob", "25", "Los Angeles"] ], "markdown": "| Name | Age | City |\\n|------|-----|--------|\\n| Alice | 30 | New York |\\n| Bob | 25 | Los Angeles |" } ] } ], "errors": [], "summary": { "inputs": 1, "results": 1, "errors": 0 }}Going Async
Section titled “Going Async”Async-capable bindings expose extraction as an awaitable operation for web servers and background workers. Synchronous bindings expose the same input and result contract directly:
Tests URI extraction API
import asynciofrom xberg import extract, ExtractInput, ExtractInputKind
async def main() -> None: input = ExtractInput(kind=ExtractInputKind("uri"), uri="https://example.com/pdf/fake_memo.pdf") result = await extract(input) print(result.results[0].content)
asyncio.run(main())Tests URI extraction API
import { ExtractInput, ExtractInputKind, extract } from "@xberg-io/xberg";async function main() { const input: ExtractInput = { kind: ExtractInputKind.Uri, uri: "https://example.com/pdf/fake_memo.pdf" }; const result = await extract(input); console.log(result.results?.[0]?.content);}
void main();Tests URI extraction API
import { WasmExtractInput, WasmExtractInputKind, extract } from "@xberg-io/xberg-wasm";async function main() { const input: WasmExtractInput = (() => { const _u0 = WasmExtractInput.default(); _u0.kind = WasmExtractInputKind.Uri; _u0.uri = "https://example.com/pdf/fake_memo.pdf"; return _u0; })(); const result = await extract(input, undefined); console.log(result.results[0].content);}
void main();Tests URI extraction API
use xberg::extract;use xberg::ExtractInput;
#[tokio::main]async fn main() { let input_json: serde_json::Value = serde_json::from_str(r#"{"kind":"uri","uri":"https://example.com/pdf/fake_memo.pdf"}"#).unwrap(); let input = serde_json::from_value::<ExtractInput>(input_json).unwrap(); let config = Default::default(); let result = extract(input, &config).await.expect("call failed"); println!("{:?}", result.results[0].content);}Tests URI extraction API
package main
import ( "fmt" xberg "github.com/xberg-io/xberg/packages/go")
func ptr[T any](value T) *T { return &value }func main() { input := xberg.ExtractInput{ Kind: ptr(xberg.ExtractInputKindURI), URI: ptr(`https://example.com/pdf/fake_memo.pdf`), } config := xberg.ExtractionConfig{} result, err := xberg.Extract(input, config) if err != nil { panic(err) } fmt.Printf("%+v\n", result.Results[0].Content)}Tests URI extraction API
import io.xberg.*;
public final class Example { public static void main(String[] args) throws Exception { var inputJson = "{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}"; var input = JsonUtil.fromJson(inputJson, ExtractInput.class); var result = Xberg.extract(input, ExtractionConfig.builder().build()); System.out.println(result.results().get(0).content()); }}Tests URI extraction API
import io.xberg.*import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
fun main() = kotlinx.coroutines.runBlocking { val mapper = jacksonObjectMapper().setPropertyNamingStrategy(com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE) val input = mapper.readValue("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", ExtractInput::class.java) val configDefault = mapper.readValue("{\"url\":{\"crawl\":{\"ssrf\":{}}}}", ExtractionConfig::class.java) val result = Xberg.extract(input, configDefault) println(result.results.first().content)}Tests URI extraction API
using System;using System.Text.Json;using Xberg;
var ConfigOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };var result = await XbergConverter.ExtractAsync(new ExtractInput { Kind = JsonSerializer.Deserialize<ExtractInputKind>("\"uri\"", ConfigOptions)!, Uri = "https://example.com/pdf/fake_memo.pdf" }, new ExtractionConfig());Console.WriteLine(result.Results[0].Content);Tests URI extraction API
import Xberg
let result = try await Xberg.extract("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", "{}")debugPrint(result.results()[0].content())Tests URI extraction API
require "xberg"result = Xberg.extract(Xberg::ExtractInput.new(kind: 'uri', uri: 'https://example.com/pdf/fake_memo.pdf'))puts result.results[0].content.inspectTests URI extraction API
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Xberg\Xberg;use Xberg\ExtractInput;$input = \Xberg\ExtractInput::from_json(json_encode(["kind" => "uri", "uri" => "https://example.com/pdf/fake_memo.pdf"]));$result = Xberg::extract($input, null);var_dump($result->getResults()[0]->content);Tests URI extraction API
input_value = %Xberg.ExtractInput{kind: "uri", uri: "https://example.com/pdf/fake_memo.pdf"}result = Xberg.extract_async(input_value)IO.inspect(Enum.at(result.results, 0).content)Tests URI extraction API
import 'dart:io';import 'package:xberg/xberg.dart';import 'package:xberg/src/xberg_bridge_generated/frb_generated.dart' show RustLib;Future<void> main() async { await RustLib.init(); try { final input = await createExtractInputFromJson(json: '{"kind":"uri","uri":"https://example.com/pdf/fake_memo.pdf"}'); final config = await createExtractionConfigFromJson(json: '{}'); final result = await XbergBridge.extract(input, config: config); stdout.writeln(result.results[0].content); } finally { RustLib.dispose(); }}Tests URI extraction API
const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { const _result_json = try xberg.extract("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}", "{}"); defer std.heap.c_allocator.free(_result_json); std.debug.print("{s}\n", .{_result_json});
}Tests URI extraction API
#include <assert.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "xberg.h"
int main(void) { XBERGAlefHandle input_handle = xberg_extract_input_from_json("{\"kind\":\"uri\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}"); XBERGAlefHandle result = xberg_extract(input_handle, 0); xberg_extract_input_free(input_handle); xberg_extraction_result_free(result); return EXIT_SUCCESS;}Next Steps
Section titled “Next Steps”You’ve covered the core API. Go deeper:
- Configuration Guide — OCR backends, chunking, language detection, config files
- Extract from Bytes — Use
ExtractInput(kind="bytes") - OCR Setup — Tesseract, PaddleOCR, Sceptre, Candle, and VLM backends
- Types Reference — Full metadata fields for every format
- Docker Deployment — Run Xberg in containers
- API Reference — Complete API documentation