v.15 modifies WAM output

Finally working with v.15 and while it is generally a good experience, I have so far one technical issue: The output from Web Application Modules (WAMs) is modified, transformed, in an extra step after the XLS transformation.

Case in point: XSL using the XHTML technology service

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" exclude-result-prefixes="lxml wd"
               xmlns:lxml="http://www.lansa.com/2002/XML/Runtime-Data"
               xmlns:wd="http://www.lansa.com/2002/XSL/Weblet-Design"
               xmlns="http://www.w3.org/1999/xhtml"
               xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:import href="std_keys.xsl" />
   <xsl:import href="std_variables.xsl" />
   <xsl:import href="std_hidden.xsl" />
   <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8"
               indent="no" />

   <xsl:template match="/">
      <html>
         <body style="background-color: grey;">
         Hello World.
         </body>
      </html>
   </xsl:template>

</xsl:transform>

which is possibly the most basic template you can write – I’ve even removed the weblet layout – is transformed to


<html xmlns="http://www.w3.org/1999/xhtml"><body data-style="background-color: grey;">
   Hello World.
</body></html>

See the differences? There’s an added namespace, (xmlns="http://www.w3.org/1999/xhtml"), and the style attribute has been transformed to a data-style attribute.

This former happens to the first tag present on the page. The latter is then fixed in the standard std_script_v2.min.js script, provided this runs – which it doesn’t in the example above, as I’ve removed the default layout.

It is not a problem in most scenarios. I expect most will continue to use WAMs to output web pages to supported browsers, and that’s fine.

The behaviour bothers me on principle. I wrote the transform, but it was transformed by another process that I cannot control. It limits me to generate output that adheres to what Lansa thinks I should be doing.

It also bothers me specifically, as I have for a short while longer, some legacy browsers I’d like to support and the new std_script_v2.min.js cannot run in those. I’ll probably work a bit on getting std_script_v2.min.js to run.

EDIT: I think I’ve found the transform that is doing this: \x_lansa\web\tsp\tsp_global_publisher.xsl:

	<!-- Change style attribute into data-style for CSP support -->
	<xsl:template match="@style">
		<xsl:attribute name="data-style"><xsl:value-of select="wd:translate(., false())"/></xsl:attribute>
	</xsl:template>

Obviously it will cause me – and especially the rest of my team – untold pain in the future if I change this but at least it gives us a hint of why it is done. Could it be Content Security Policy? Yes, it appears so. In that case, I’ll accept that it is an elegant solution to a problem that would probably have stumped me, for a while.

I still think I should have the option of using it or not and unlike Web Pages, there are no settings for WAMs so I can’t adjust it.

Response(*JSON) and invalid values

We still haven’t upgraded but at least we have it on our schedule. So this is at least in v.12 but I suspect it also applies in later versions.

I have a lot of webroutines that returns JSON but often I have had to generate the JSON by hand, which obviously is less than optimal. So when I get the chance I use Response(*JSON), like:

Webroutine Name(status) Response(*JSON) Desc('lagerstatus') Onentry(SESSIONSTATUS_NONE)

While this returns rather convoluted JSON it generally works. Except, when it doesn’t:

{"value":.00}

This is not a valid JSON, it should have been

{"value":0.00}

Unfortunately no edit code makes this possible so I have to skip Response(*JSON) and instead build the JSON myself.

I am looking forward to upgrading

We are still at v.14.1 and v.12 but will soon be upgrading to v.14.2 and v.15, respectively. That’s good.

Unfortunately, I doubt upgrading from v.14.1 to v.14.2 will solve the basic XSLT editing problems in the Lansa editor. Currently, I had a WAM fail when I had saved this XSLT/XML

<tr><input id="{$WSSHPLNR/@id}" type="hidden" name="{$WSSHPLNR/@id}" value="{$WSSHPLNR}" /><td ...

and when I, the next day, loaded the WAM, or whenever I switch between the “XSL” and “Web Page” tabs in the design tab, it gets changed to

<tr /><input id="{$WSSHPLNR/@id}" type="hidden" name="{$WSSHPLNR/@id}" value="{$WSSHPLNR}" /><td ...

Solution? Move the <input> tag to before the <tr> tag. Yes, I know, I should have done that anyway, but the editor shouldn’t make my content illegal when I switch tabs.

Server modules live separate lives

As much of the other posts I write here, this relates to something that surprised me.

Currently I write a lot of server modules as APIs, and this time I needed to submit a job for some processing. But for some reason this failed and I couldn’t find a reason.

That wasn’t really a problem, because I could just save the data I needed to process in a saved list and have a batch job read the list and do the processing.

Except, that didn’t work either.

Maybe that’s what Lansa means by

SAVE_LIST and RESTORE_SAVED_LIST should be used in the same context. That is, you should not use SAVE_LIST from within a function run on the WEB and later restore the saved list from within a function run as a Visual LANSA function.

Because even though the saved list was stored in DC@F80, the F80P#I field was not set to the partition I was using. It was set to “SYS”. So, in the batch job I couldn’t read the saved list, because the batch job was a regular function.

Adjust for a Datetime

The Date type has an Adjust intrinsic, which I commonly use for numbers as

#FAKYMD := #FAKYMD.AsDate( CCYYMMDD ).Adjust( -30 ).AsNumber( CCYYMMDD )

The Datetime type has no such intrinsic, but when I end up with a datetime stored in a number, I have used this roundabout way:

#FAKTIME := ((#FAKTIME / 1000000).AsDate( CCYYMMDD ).Adjust( -30 ).AsNumber( CCYYMMDD ) * 1000000) + (#FAKTIME.Mod( 1000000 ))

#FAKYMD is 8 digits, YYYYMMDD, #FAKTIME is 14 digits, YYYYMMDDhhmmss, in my examples.

 

Writing space to a file

This should be easy, but it’s not in RDML. The current solution I have is using HEXTOBIN and binary writing.

I am writing to a file and need to write a space character in certain situations. The codepage of the file is Windows-1252 (mostly equivalent to Latin1 or ISO-8859-1).

I opened the file with

Use Builtin(STM_FILE_OPEN) With_Args(#FILENAME 'APPEND TEXT LINETERMINATOR=NONE CODEPAGE=1252') To_Get(#FILENO #RETNCODE)

but if try to output a space character it gets trimmed and no space is added to the file. Instead I close, open, close and re-open:

Use Builtin(STM_FILE_OPEN) With_Args(#FILENAME 'APPEND BINARY LINETERMINATOR=NONE') To_Get(#FILENO #RETNCODE)
Use Builtin(HEXTOBIN) With_Args('20' Y) To_Get(#WCHAR1)
Use Builtin(STM_FILE_WRITE) With_Args(#FILENO2 #WCHAR1) To_Get(#RETNCODE)
Use Builtin(STM_FILE_CLOSE) With_Args(#FILENO2)
Use Builtin(STM_FILE_OPEN) With_Args(#FILENAME 'APPEND TEXT LINETERMINATOR=NONE CODEPAGE=1252') To_Get(#FILENO #RETNCODE)

This paradoxically only worked because I am running on a different codepage than Windows-1252, so the binary value 0x20 is not considered a space character (it’s Digit Select, whatever that is).

No, it’s not efficient.

Length of string

In RDMLX, easy, just

#LEN := #STR.CurChars

But in RDML it’s not so easy and for some reason there’s not even a buit-in function to return the length of a string.

So I made this:

Define Field(#W_C256) Type(*CHAR) Length(256)
Define Field(#W_C256_B) Type(*CHAR) Length(256)
Define Field(#W_C1) Type(*CHAR) Length(1)
Define Field(#W_D3_0) Type(*DEC) Length(3) Decimals(0)

Subroutine Name(LENGTH) Parms((#W_C256 *RECEIVED) (#W_D3_0 *RETURNED))
  Use Builtin(RIGHT) With_Args(#W_C256) To_Get(#W_C256_B)
  Substring Field(#W_C256_B 256 1) Into_Field(#W_C1)
  Use Builtin(REVERSE) With_Args(#W_C256) To_Get(#W_C256_B)
  Use Builtin(SCANSTRING) With_Args(#W_C256_B #W_C1) To_Get(#W_D3_0)
  Change Field(#W_D3_0) To('(256 + 1) - #W_D3_0')
Endroutine

which I then include when necessary.

Select_Sql does not validate SQL source

I made this error and spent a long time trying to spot it:

Select_Sql Fields((#ANTAL 'SUM(ANTAL')) From_Files(TRANS) Where(...)
...
Endselect

That is how I learned that the optional SQL source for a field is not validated in the editor or during compilation. Adding the missing end-parenthesis fixed my error:

                                    |
                                    V
Select_Sql Fields((#ANTAL 'SUM(ANTAL)')) From_Files(TRANS) Where(...)
...
Endselect

You got me there

Working with CONDCHECK I got confused. The condition check works to mark a field that is filled out incorrectly, but the condition is to be read as “these conditions should be satisfied, if not…”.

Which makes sense; you write the condition that you want satisfied. If it isn’t you get the message.

My problem was that I thought of it in the context of if … then; if this condition is satisfied, I should get the message. Which I now realise was wrong.