speedata / publisher

speedata Publisher - a professional database Publishing system
https://www.speedata.de/
GNU Affero General Public License v3.0
292 stars 36 forks source link

`<ClearPage/>` inside a variable #412

Closed pr-apes closed 1 year ago

pr-apes commented 2 years ago

@pgundlach

<ClearPage/> seems to break Publisher when inside a variable:

I invoke sp --dummy --autoopen -v image_file=../document.pdf with the following layout:

<Layout xmlns="urn:speedata.de:2009/publisher/en"
  xmlns:sd="urn:speedata:2009/publisher/functions/en">

<SetVariable variable="a_b_c">
  <Loop select="sd:number-of-pages($image_file)" variable="page_number">
    <PlaceObject row="0cm" column="0cm">
      <Image file="{$image_file}" page="{$page_number}"/>
    </PlaceObject>
    <ClearPage/>
  </Loop>
</SetVariable>

  <Record element="data">
    <Copy-of select="$a_b_c"/>
  </Record>
</Layout>

And I get the following error message:

Searching for image "../document.pdf"
Page of type "Default Page" created (1)
Number of rows: 28, number of columns = 19
Error: [page 1] D:\tools\speedata-publisher\sw/lua/publisher.lua:2763: bad argument #3 to 'format' (number expected, got nil)
stack traceback:
        ...\speedata-publisher\sw/lua/publisher\spinit.lua:54: in function 'call'
        ...\speedata-publisher\sw/lua/publisher\spinit.lua:389: in function 'main_loop'
        ...\speedata-publisher\sw/lua/publisher\spinit.lua:398: in main chunk
        [C]: in function 'require'
        [\directlua]:1: in main chunk
Stop processing data
1 errors occurred
Duration: 0.025000 seconds

If I remove (or comment out) <ClearPage/> from the layout, everythings works fine.

I'm afraid this may be a bug.

Many thanks for your help.

pgundlach commented 2 years ago

Variables must not contain outputting commands such as PlaceObject or ClearPage. I will update the documentation for the next version

pr-apes commented 2 years ago

I see. I wonder whether there may be another way to call fragments of code with that kind of commands inside.

Imagine a <Record element="data"> such as in:

<Record element="data">
  <Switch>
    <Case test="sd:mode('first')">
      <Copy-of select="$first"/>
    </Case>
    <Case test="sd:mode('second')">
      <Copy-of select="$second"/>
    </Case>
    <Case test="sd:mode('third')">
      <Copy-of select="$third"/>
    </Case>
    <Case test="sd:mode('fourth')">
      <Copy-of select="$fourth"/>
    </Case>
    <Case test="sd:mode('fifth')">
      <Copy-of select="$fifth"/>
    </Case>
    <Case test="sd:mode('sixth')">
      <Copy-of select="$sixth"/>
    </Case>
  </Switch>
</Record>

This comes for my first usage of Publisher (only modes and variable names have been replaced).

Having a way to invoke code fragments helps the error detection in conditionals (among other things).

Many thanks for your help again.

pgundlach commented 2 years ago

You can use something like this:

<Layout xmlns="urn:speedata.de:2009/publisher/en"
    xmlns:sd="urn:speedata:2009/publisher/functions/en">

    <Record element="data">
        <SetVariable variable="var">
            <Element name="a">
                <Attribute name="greeting" select="'Hello world!'" />
            </Element>
        </SetVariable>
        <ProcessNode select="$var" />
    </Record>

    <Record element="a">
        <PlaceObject>
            <Textblock>
                <Paragraph>
                    <Value select="@greeting"></Value>
                </Paragraph>
            </Textblock>
        </PlaceObject>
    </Record>
</Layout>

(perhaps I should document this as well...)

pr-apes commented 2 years ago

Many thanks for your reply.

pr-apes commented 2 years ago

@pgundlach,

I'm afraid that I cannot use this in practice (code would be more complex than the problem it intends to solve).

I wonder whether there could be a <DelayExpansion> element, that only reads the command in a variable when the variable is invoked.

Such an element would enabled the following snippet:


<SetVariable variable="a_b_c">
  <DelayExpansion>
    <ClearPage/>
  </DelayExpansion>
</SetVariable>

<Record element="data">
  <Copy-of select="$a_b_c"/>
</Record>

Many thanks for your help.

pgundlach commented 2 years ago

It would be rather easy to do something like this:

<Layout xmlns="urn:speedata.de:2009/publisher/en"
    xmlns:sd="urn:speedata:2009/publisher/functions/en">
    <Pageformat height="5cm" width="7cm" />
   <!-- or execute= now/later - default would be now -->
    <SetVariable variable="foo" dontexecute="yes">
        <PlaceObject>
            <Textblock>
                <Paragraph>
                    <Value>Hello</Value>
                </Paragraph>
            </Textblock>
        </PlaceObject>
        <ClearPage/>
        <PlaceObject>
            <Textblock>
                <Paragraph>
                    <Value select="$greeting"></Value>
                </Paragraph>
            </Textblock>
        </PlaceObject>
    </SetVariable>

    <Record element="data">
        <!-- error, $greeting not set-->
        <Copy-of select="$foo"/>
        <SetVariable variable="greeting" select="'pr-apes'"/>
        <Copy-of select="$foo"/>
    </Record>
</Layout>

What do you think?

pr-apes commented 2 years ago

I think it would be great, if this would allow the following too (which I guess it would be possible too):

<Layout xmlns="urn:speedata.de:2009/publisher/en"
    xmlns:sd="urn:speedata:2009/publisher/functions/en">
    <Pageformat height="5cm" width="7cm" />
    <SetVariable variable="foo" execute="later">
        <PlaceObject>
            <Textblock>
                <Paragraph>
                    <Value>Hello</Value>
                </Paragraph>
            </Textblock>
        </PlaceObject>
        <ClearPage/>
        <PlaceObject>
            <Textblock>
                <Paragraph>
                    <Value>Hello again.</Value>
                </Paragraph>
            </Textblock>
        </PlaceObject>
    </SetVariable>

    <Record element="data">
        <Copy-of select="$foo"/>
    </Record>
</Layout>

I also think that execute may be a better name for the attribute, being now (default) and later the values.