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

Spurious Combinator error with default template #95

Open
emarsden opened this issue Aug 8, 2024 · 9 comments
Open

Spurious Combinator error with default template #95

emarsden opened this issue Aug 8, 2024 · 9 comments
Assignees
Labels
bug Something isn't working

Comments

@emarsden
Copy link

emarsden commented Aug 8, 2024

An XSL template that includes the following "pass-through" rule will generate a spurious Combinator error in xslt::from_document (using the sample code for the xrust:xslt module, simply with this added to the sample XSLT).

  <xsl:template match='@*|node()'>
    <xsl:copy>
      <xsl:apply-templates select='@*|node()'/>
    </xsl:copy>
  </xsl:template>

@ballsteve ballsteve self-assigned this Aug 8, 2024
@ballsteve ballsteve added the bug Something isn't working label Aug 8, 2024
@ballsteve
Copy link
Owner

Thanks for the bug report. Union operations haven't been tested very thoroughly, so I'll add in this example to the test suite and then look at where the problem is. This will be in the XPath parser, pattern matching and expression transformation.

@emarsden
Copy link
Author

The error for this example has now changed (using the "dev" branch): I see

thread 'main' panicked at /home/emarsden/.cargo/git/checkouts/xrust-bdc2299a4e8ad91c/65a2b9d/src/xslt.rs:399:47:
index out of bounds: the len is 0 but the index is 0

with an input XSLT of

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

@heaths
Copy link

heaths commented Nov 13, 2024

I tried splitting the templates to avoid the OR, but then node() was erring with undefined function: "name test node". Commenting that whole template out now, I get `already borrowed: BorrowMutError1.

My code is the same as in your docs for transforming XML, sans some variable name changes.

@ballsteve
Copy link
Owner

Are you able to add a test case for this into the test suite? Send through a PR

@ballsteve
Copy link
Owner

I've created a new branch for this issue - issue-95. I'll be pushing this to the repo shortly

@heaths
Copy link

heaths commented Nov 26, 2024

Sorry for the delay. Here's a simple repro for the combinator. I applied a workaround but getting a "union_expr" error in test_transform_split that I don't recall getting before. I'll try to see if I can repro it again, but I may have lost some context since it's been a while.

Repro code
#![allow(dead_code)]

use xrust::{
    parser::xml::parse, transform::context::StaticContextBuilder, trees::smite::RNode,
    xslt::from_document, ErrorKind, Item, Node, SequenceTrait,
};

fn transform(template: &'static str) -> Result<String, xrust::Error> {
    const XML: &str = r#"<?xml version="1.0"?>
        <root>
            <child id="1"/>
            <child Id="2"/>
        </root>
    "#;

    let xmldoc = Item::Node(make_from_str(XML)?);
    let xsldoc = make_from_str(template)?;

    let mut static_content = StaticContextBuilder::new()
        .fetcher(|_| {
            Err(xrust::Error::new(
                ErrorKind::NotImplemented,
                "not implemented",
            ))
        })
        .message(|_| Ok(()))
        .parser(|_| {
            Err(xrust::Error::new(
                ErrorKind::NotImplemented,
                "not implemented",
            ))
        })
        .build();

    let mut ctx = from_document(xsldoc, None, make_from_str, |_| Ok(String::new()))?;
    ctx.context(vec![xmldoc], 0);
    ctx.result_document(RNode::new_document());

    let xml = ctx.evaluate(&mut static_content)?;
    Ok(xml.to_xml())
}

fn make_from_str(s: &str) -> Result<RNode, xrust::Error> {
    let doc = RNode::new_document();
    let _ = parse(doc.clone(), s, None)?;
    Ok(doc)
}

#[test]
fn test_transform_combined() {
    const XSL: &str = r#"
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:output method="xml" version="1.0"/>
            <xsl:template match="node() | @*">
                <xsl:copy>
                    <xsl:apply-templates select="node() | @*"/>
                </xsl:copy>
            </xsl:template>
        </xsl:stylesheet>
    "#;

    let actual = transform(XSL).unwrap();
    println!("{actual}");
}

#[test]
fn test_transform_split() {
    const XSL: &str = r#"
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:output method="xml" version="1.0"/>
            <xsl:template match="node()">
                <xsl:copy>
                    <xsl:apply-templates select="node() | @*"/>
                </xsl:copy>
            </xsl:template>
            <xsl:template match="@*">
                <xsl:copy/>
            </xsl:template>
        </xsl:stylesheet>
    "#;

    let actual = transform(XSL).unwrap();
    println!("{actual}");
}

@ballsteve
Copy link
Owner

The main problem is the union operator in the match pattern. I'm working on that now. Keep track of progress in the issue-95 branch.

@heaths
Copy link

heaths commented Nov 30, 2024

The undefined function: "name test node" appears to be coming from a lone:

<xsl:apply-templates select="node()"/>

Same basic repro as I already pasted, but I commented out xsl:template elements. More specifically, my stylesheet is below and applies over a criterion SVG report:

Repro: see BUGBUG line
<xsl:stylesheet version="1.0"
  xmlns:svg="http://www.w3.org/2000/svg"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="utf-8" cdata-section-elements="style"/>
  <xsl:template match="svg:svg">
    <xsl:element name="svg" namespace="http://www.w3.org/2000/svg">
      <xsl:apply-templates select="@*"/>

      <!-- Use @media queries to stylize text for readability in different themes -->
      <xsl:element name="style" namespace="http://www.w3.org/2000/svg">
        <xsl:attribute name="style">text/css</xsl:attribute>
        <xsl:text disable-output-escaping="yes"><![CDATA[
          text { fill: #000000 }
          polyline { fill: none; stroke: #000000 }
          @media (prefers-color-scheme: dark) {
            text { fill: #ffffff }
            polyline { fill: none; stroke: #ffffff }
          }
        ]]></xsl:text>
      </xsl:element>

      <!-- BUGBUG: <xsl:apply-templates select="node()"/> -->
    </xsl:element>
  </xsl:template>

  <!-- Remove the "Input" label that overlaps Y axis labels -->
  <!-- <xsl:template match="svg:text[normalize-space() = 'Input']"/> -->

  <!-- Remove hardcoded colors I want to vary on @media queries -->
  <!-- <xsl:template match="svg:text[@fill = '#000000']/@fill"/>
  <xsl:template match="svg:polyline[@stroke = '#000000']/@stroke"/> -->

  <!-- Split templates because of https://github.com/ballsteve/xrust/issues/95 -->
  <!-- <xsl:template match="node()">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="@*">
    <xsl:copy/>
  </xsl:template> -->
</xsl:stylesheet>

With that commented out, I get an already borrowed: BorrowMutError error. The rust code is the same as above.

Updated: I see that node() isn't a supported function:

}) => match localpart.to_string().as_str() {

This has always been used in an identity template, but I see from https://developer.mozilla.org/docs/Web/XPath/Functions it's not actually defined as a function. If I change node() to *, I still get the already borrowed: BorrowMutError, though. The stack trace follows, but this appears to be coming from src/trees/smite.rs:902 in trust 1.2.0.

Stack trace
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
     Running `target/debug/xtask docgen`
thread 'main' panicked at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/trees/smite.rs:902:59:
already borrowed: BorrowMutError
stack backtrace:
   0: rust_begin_unwind
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/std/src/panicking.rs:662:5
   1: core::panicking::panic_fmt
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/panicking.rs:74:14
   2: core::cell::panic_already_borrowed
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/cell.rs:789:5
   3: core::cell::RefCell<T>::borrow_mut
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/cell.rs:1080:25
   4: xrust::trees::smite::make_parent
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/trees/smite.rs:902:57
   5: xrust::trees::smite::unattached
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/trees/smite.rs:880:13
   6: xrust::trees::smite::<impl xrust::item::Node for alloc::rc::Rc<xrust::trees::smite::Node>>::pop
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/trees/smite.rs:440:33
   7: xrust::trees::smite::<impl xrust::item::Node for alloc::rc::Rc<xrust::trees::smite::Node>>::add_attribute
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/trees/smite.rs:536:17
   8: xrust::transform::construct::copy
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/construct.rs:348:52
   9: xrust::transform::context::Context<N>::dispatch
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:380:38
  10: xrust::transform::construct::make_sequence::{{closure}}
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/construct.rs:318:21
  11: core::iter::traits::iterator::Iterator::try_fold
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/iter/traits/iterator.rs:2405:21
  12: xrust::transform::construct::make_sequence
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/construct.rs:317:5
  13: xrust::transform::context::Context<N>::dispatch
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:379:44
  14: xrust::transform::template::apply_templates::{{closure}}
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/template.rs:136:21
  15: core::iter::traits::iterator::Iterator::try_fold
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/iter/traits/iterator.rs:2405:21
  16: xrust::transform::template::apply_templates
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/template.rs:108:5
  17: xrust::transform::context::Context<N>::dispatch
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:393:51
  18: xrust::transform::construct::make_sequence::{{closure}}
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/construct.rs:318:21
  19: core::iter::traits::iterator::Iterator::try_fold
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/iter/traits/iterator.rs:2405:21
  20: xrust::transform::construct::make_sequence
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/construct.rs:317:5
  21: xrust::transform::context::Context<N>::dispatch
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:379:44
  22: xrust::transform::construct::element
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/construct.rs:101:5
  23: xrust::transform::context::Context<N>::dispatch
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:371:42
  24: xrust::transform::construct::make_sequence::{{closure}}
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/construct.rs:318:21
  25: core::iter::traits::iterator::Iterator::try_fold
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/iter/traits/iterator.rs:2405:21
  26: xrust::transform::construct::make_sequence
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/construct.rs:317:5
  27: xrust::transform::context::Context<N>::dispatch
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:379:44
  28: xrust::transform::template::apply_templates::{{closure}}
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/template.rs:136:21
  29: core::iter::traits::iterator::Iterator::try_fold
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/iter/traits/iterator.rs:2405:21
  30: xrust::transform::template::apply_templates
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/template.rs:108:5
  31: xrust::transform::context::Context<N>::dispatch
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:393:51
  32: xrust::transform::context::Context<N>::evaluate::{{closure}}
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:255:30
  33: core::option::Option<T>::map_or_else
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/option.rs:1210:24
  34: xrust::transform::context::Context<N>::evaluate
             at /Users/heaths/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xrust-1.2.0/src/transform/context.rs:238:13
  35: xtask::docgen::Command::run
             at ./xtask/src/docgen.rs:53:19
  36: xtask::main
             at ./xtask/src/main.rs:26:33
  37: core::ops::function::FnOnce::call_once
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

@ballsteve
Copy link
Owner

The issue-95 branch has the fix and has been promoted as a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants