Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

XPath

An XPath 1.0 expression and predicate language over sxd-document and sxd-xpath. It evaluates //node and /path queries against an Exchange XML body.

    ctx.register_language("xpath", Box::new(XPathLanguage::new()))
        .expect("xpath not yet registered"); // allow-unwrap

    let lang = XPathLanguage::new();

    let title_expr = lang
        .create_expression("/catalog/book[1]/title")
        .expect("valid expression"); // allow-unwrap

    let in_stock_pred = lang
        .create_predicate("/catalog/book[@in-stock='true']")
        .expect("valid predicate"); // allow-unwrap

    let title_expr = Arc::new(title_expr);
    let in_stock_pred = Arc::new(in_stock_pred);
    let route = RouteBuilder::from("timer:tick?period=800&repeatCount=6")
        .route_id("language-xpath-demo")
        .process(move |mut exchange: camel_api::Exchange| {
            let c = Arc::clone(&counter_clone);
            Box::pin(async move {
                let n = c.fetch_add(1, Ordering::SeqCst) as usize;
                let (title, in_stock) = books[n % books.len()];
                let xml = format!(
                    "<catalog><book id=\"{}\" in-stock=\"{}\"><title>{}</title></book></catalog>",
                    n + 1,
                    in_stock,
                    title
                );
                exchange.input.body = Body::Xml(xml);
                Ok(exchange)
            })
        })
        .process({
            let expr = Arc::clone(&title_expr);
            move |mut exchange: camel_api::Exchange| {
                let expr = Arc::clone(&expr);
                Box::pin(async move {
                    if let Ok(value) = expr.evaluate(&exchange).await
                        && let Some(name) = value.as_str()
                    {
                        exchange
                            .input
                            .set_header("book-title", camel_api::Value::String(name.to_string()));
                    }
                    Ok(exchange)
                })
            }
        })
        .to("log:all-books?showBody=true&showHeaders=true")
        .filter({
            let pred = Arc::clone(&in_stock_pred);
            let handle = tokio::runtime::Handle::current();
            move |ex: &camel_api::Exchange| handle.block_on(pred.matches(ex)).unwrap_or(false)
        })
        .to("log:in-stock?showBody=true&showHeaders=true")
        .end_filter()
        .build()?;
YAML equivalent
- id: language-xpath-demo
  from: timer:tick?period=800&repeatCount=6
  steps:
    - set_body:
        value: "<catalog><book in-stock='true'><title>The Rust Book</title></book></catalog>"
    - set_header:
        key: title
        xpath: "/catalog/book[1]/title"
    - to: log:all-books?showBody=true&showHeaders=true
    - filter:
        xpath: "/catalog/book[@in-stock='true']"
        steps:
          - to: log:in-stock?showBody=true&showHeaders=true

You register xpath into CamelContext by name, then build expressions and predicates up front. The included example constructs one expression (/catalog/book[1]/title) and one predicate (/catalog/book[@in-stock='true']) before the route. Expressions extract values from the XML body. Predicates gate filter steps.

The XPath query is trusted operator configuration. The XML body is untrusted, adversary-controlled data under ADR-0032. Exchange data never enters the query string. max_input_bytes bounds the raw XML body before parsing. The default is 1 MiB. Both sxd-document and sxd-xpath are pure Rust and register no filesystem or network resolver. The parser has no <!ENTITY> declaration handler. Recursive entity expansion, including a billion-laughs payload, is structurally unavailable. External entity declarations cannot trigger a file or network fetch.

Known limitations apply. Namespace prefixes are unsupported because the evaluation context has no prefix-to-URI map. Evaluation has no wall-clock timeout. The query is trusted, and the untrusted XML input has a byte bound. The sxd-xpath library is unmaintained. A replacement must preserve the security posture above.

Use XPath when the body carries XML and you need to select elements or test attributes. For structured JSON bodies, use JSONPath.

Reference: Language SPI · XPath crate