Question
· Nov 21

Defining Fixed-Length String Properties in a Class

I'm attempting to streamline a process for renaming PDF documents received from multiple vendors to conform to a specification provided by an EMR vendor for ingestion. Things like Document ID, Document Type, Date of Service, Account Number, MRN, etc. all must be included in the filename at defined offsets and lengths. Most of the required values can be extracted from the inbound file's name and the few remaining are static values that would be the same (or handled via a lookup table based on source) for all documents. The inbound and outbound filenames are essentially fixed-width records with each value appearing at a specific offset and space-padded on the right when needed.

I'd like to model the output format in something that can be used in the DTL editor, subclassing the Ens.StreamContainer class and extending it to represent the individual filename field elements as properties that can have values mapped to them. The properties would have a MAXLEN attribute set that matches each individual field width. I would then override the OutputFilename property as calculated to assemble the fields in the correct order, offset and length. I'd like to be able to refer to each property's MAXLEN attribute programmatically to perform that assembly.

Since these PDFs may come from many sources, I don't think I need to worry much about modeling each inbound filename format; I'd simply use $EXTRACT to obtain the needed values. But having a template for the outbound filename would be a significant time saver and simplify things for those that will eventually have to take over supporting this integration.

Any thoughts on how this might be accomplished would be very much appreciated!

Product version: IRIS 2023.1
Discussion (7)2
Log in or sign up to continue

For defining a fixed length string field in a class definition, you can use the MINLEN and MAXLEN parameters in tandem: https://docs.intersystems.com/iris20231/csp/documatic/%25CSP.Documatic.c...

This will not pad the string automatically, however, you would need to pad it to the desired length before saving an instance of the class.

To retrieve the MAXLEN, this answer to an earlier question may be helpful : https://community.intersystems.com/post/getting-parameters-cleanly-prope...

So the call might look something like:

$$$defMemberArrayGet(class,$$$cCLASSproperty,prop,$$$cPROPparameter,"MAXLEN")

EDIT: These macros aren't available on recent versions, here's an object-oriented way to do it (that's cleaner anyway):
 

I've confirmed that this works on a 2024.1.1 instance with the following steps:

set cdef = ##class(%Dictionary.ClassDefinition).%OpenId("<class name>")
Set count = cdef.Properties.Count()
for i = 1:1:count {if cdef.Properties.GetAt(i).Name = "<Property Name>" {w cdef.Properties.GetAt(i).Parameters.GetAt("MAXLEN")}}

Didn't realize that, sorry! I should have done more testing myself. I did some more research and found a way to do this in an object-oriented fashion: https://community.intersystems.com/post/get-property-maxlen 

I've confirmed that this works on a 2024.1.1 instance with the following steps:

set cdef = ##class(%Dictionary.ClassDefinition).%OpenId("<class name>")
Set count = cdef.Properties.Count()
for i = 1:1:count {if cdef.Properties.GetAt(i).Name = "<Property Name>" {w cdef.Properties.GetAt(i).Parameters.GetAt("MAXLEN")}}

Thanks, this is useful @Nick Petrocelli! It appears that the order in which the properties are returned by iterating with Count() is sorted alphabetically. Is there any way to fetch them in the order in which they were defined in the class? I have SqlColumnNumber assigned for each of the properties, so if there's a way to fetch that keyword's value I can order them according to that. I'd prefer not to hard-code them in if possible, as the spec may change ...

Thanks!

Hi @Jeffrey Drumm ;
different approach: use your own datatype that always returns fixed MAXLEN string:

 

/// Make fixlength String according to MAXLEN parameter
Class rcc.GetFix Extends %Library.String
{
/// Fill value <var>%val</var> to <a href="#MAXLEN">MAXLEN</a> characters.
Method Get() As %String [ CodeMode = generator, ServerOnly = 1 ]
{
	set code="$e(%val_"""_$j("",+%parameter("MAXLEN"))
	set code=code_""",1,"_+%parameter("MAXLEN")_")"
	$$$GENERATE( "  Quit "_code)
	QUIT $$$OK
}
}

and a test class:

Class rcc.FixTest Extends %RegisteredObject
{
Property test As rcc.GetFix(MAXLEN = 12);
}

and now some check from terminal:
 

SAMPLES>set z=##class(rcc.FixTest).%New() set z.test="rob"
SAMPLES>write z.test,$L(z.test)
rob         12

SAMPLES>;some oversized string
SAMPLES>set z.test=";some oversized string"
SAMPLES>write z.test,$L(z.test)
;some oversi12
SAMPLES>  

Hope this helps you along