Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First crack at custom xpath functions #117

Closed
wants to merge 2 commits into from

Conversation

zackpcodes
Copy link

@zackpcodes zackpcodes commented Oct 19, 2024

I am rather new to Rust and the XRust library so i apologize for my blunders in advance haha. This seems to do what my team needs. I tested with the following snippet.


    fn make_from_str(s: &str) -> Result<RNode, Error> {
        let doc = Rc::new_document();
        let e = parse(doc.clone(), s, None)?;
        Ok(doc)
    }
    
    // The source document (a tree)
    let src = Item::Node(
        make_from_str("<Example><Title>XSLT in Rust</Title><Paragraph>A simple document.</Paragraph></Example>")
        .expect("unable to parse XML")
    );
    
    // The XSL stylesheet
    let style = make_from_str("<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
      <xsl:template match='child::Example'><html><xsl:value-of select=\"custom()\"/><xsl:apply-templates/></html></xsl:template>
      <xsl:template match='child::Title'><head><title><xsl:apply-templates/></title></head></xsl:template>
      <xsl:template match='child::Paragraph'><body><p><xsl:apply-templates/></p></body></xsl:template>
    </xsl:stylesheet>")
        .expect("unable to parse stylesheet");
    
    // Create a static context (with dummy callbacks)
    let mut static_context = StaticContextBuilder::new()
        .message(|_| Ok(()))
        .fetcher(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented")))
        .parser(|_| Err(Error::new(ErrorKind::NotImplemented, "not implemented")))
        .build();
    
    // Compile the stylesheet
    let mut ctxt = from_document(
        style,
        None,
        make_from_str,
        |_| Ok(String::new())
    ).expect("failed to compile stylesheet");

    // register custom function
    fn custom<N: Node>(args: &Vec<Transform<N>>) -> Result<Sequence<N>, Error> {
        println!("in custom");
        // random return value used to test
        Ok(vec![Item::Value(Rc::new(Value::Boolean(true)))])
    }
    
    // Set the source document as the context item
    ctxt.context(vec![src], 0);
    ctxt.register_ext_function("custom".to_string(), custom);
    // Make an empty result document
    ctxt.result_document(Rc::new_document());
    
    // Let 'er rip!
    // Evaluate the transformation
    let seq = ctxt.evaluate(&mut static_context)
        .expect("evaluation failed");
    fs::write("test.xml", seq.to_xml()).expect("Unable to write file");

@ballsteve
Copy link
Owner

Firstly, please work on the extensions branch rather than dev.

This PR deals with extension functions, but not elements. That's OK - we have to start somewhere ;-)

It is not really compatible with how extensions in XSLT work. Firstly, the name of the function must be a QName with a non-null namespace URI (see XSLT section 24).

I think the Transform::Extension variant should include a compile-time data object. Otherwise, this is looking like a workable solution.

Also, the function-available() function should return true for that function name. However, we can work on that part later.

@zackpcodes
Copy link
Author

Understood. I will work on getting that fixed up and off the extensions branch. Thanks for taking a look!

@ballsteve ballsteve self-requested a review October 21, 2024 01:06
@zackpcodes zackpcodes closed this Oct 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants