crs4 / hl7apy

Python library to parse, create and handle HL7 v2 messages.
http://crs4.github.io/hl7apy/
MIT License
215 stars 85 forks source link

The latest version eats ampersands for some reason #100

Open JomoliTech opened 2 years ago

JomoliTech commented 2 years ago

For example, setting MSH_2='^~\&' or '^~\&' or any combination of slashes or even hard-coding the character with the unicode character number, the ampersand refused to be there. Using u' strings also doesn't work. Printing the message, any and all ampersands are gone. And even more, if you have another element with an ampersand in it, the whole thing becomes a None type.

This is the last thing remaining on my project is getting the & to print in a message =/

svituz commented 2 years ago

I'm not experiencing problems with ampersands.

BTW it's not necessary to set MSH_2 if you use the default one, it is already set by the module.

That said, if I do

m = Message("RSP_K21")
m.msh.msh_2 = '^~\\&'
print(repr(m.to_er7()))

I correctly get:

'MSH|^~\\&|||||20220204105942|||||2.5'

Please, be more specific. If you can, provide an example, thanks

JomoliTech commented 2 years ago

For me m = Message() del m.msh s = Segment('MSH') f=Field('MSH_2') f.value='^~\\&' ...

right at that point of assigning the value, to f,
f.value becomes '^~\\' in my case the 'MSH_2' is coming from the element.tag and the f.value is coming from the element.text attributes in lxml. And there's no way for me to make it anything else. Even if I just try to '&' it still disappears. The reason I'm doing it this way is because I need to build the message dynamically depending on the fields/elements in the XML received. And you can't pass variables as the message segments. e.g.-m.msh.currfield=currfield.value

I'm having the same issue in the segment MSH_3 and component HD_1. Basically it seems you can only add & if and only if you add it the child traversal way.

svituz commented 2 years ago

Very strange behavior you've discovered :) I've never deleted MSH but it is probably causing some problems. In the least case, I think there's no point in doing that. By default, the module creates it and fills it just with MSH.1 MSH.2, MSH.7 and MSH.12 fields that can be all overwritten. MSH.1 and MSH_2 are particular fields to customize. If you need to do that, you have to pass to the message an encoding_chars dictionary when instantiating it. You can learn more in paragraph encoding in the guide.

I tried changing MSH.3 and I don't have any problem.

m = Messasge()
m.msh.msh_3 = "try&ampp&rs&nd"
print(repr(m.to_er7())

I get MSH|^~\\&|try&appers&nd||||20220204213632|||||2.5'

Hope that solves your issue

JomoliTech commented 2 years ago

Yeah, I wasn't trying to delete it originally, but when I validated it, I was getting extra MSH segments. I was just trying to pass the elements from the xml to the HL7 segment/field/components dynamically. So I could go essentially:

s=segment(element.tag) f=Field(childElement.tag) f.value=childElement.value c=Component(grandChildElement.tag) c.value=grandChileElement.value

In the end I made a dictionary that each key's value so it calls a function that populates the proper segments. So if the XML skips them I don't overwrite it. Just was a weird thing I wasn't expecting as I just wanted to create the message from scratch.

JomoliTech commented 2 years ago

``

Very strange behavior you've discovered :) I've never deleted MSH but it is probably causing some problems. In the least case, I think there's no point in doing that. By default, the module creates it and fills it just with MSH.1 MSH.2, MSH.7 and MSH.12 fields that can be all overwritten. MSH.1 and MSH_2 are particular fields to customize. If you need to do that, you have to pass to the message an encoding_chars dictionary when instantiating it. You can learn more in paragraph encoding in the guide.

I tried changing MSH.3 and I don't have any problem.

m = Messasge()
m.msh.msh_3 = "try&ampp&rs&nd"
print(repr(m.to_er7())

I get MSH|^~\\&|try&appers&nd||||20220204213632|||||2.5'

Hope that solves your issue

I think the ampersand is broken in the thing.value= method of assignation. Doing it in the child traversal way works, doing it with .value= does not.

c.value='\&' or anything with an '&' truncates or nulls the actual text value.

   s=segment("MSH_3")
   c=Component("HD_1")
   c.value='Children & Family'

Gives me a None type error.

svituz commented 2 years ago

I still cannot reproduce the error.

c = Component("HD_1")
>>> c.value = "Children & fmaily"
>>> c.value
'Children & family'
>>> c.value = "\&"
>>> c.value
'\\E\\&'

which is correct.

s = Segment("MSH_3") raises a InvalidName exception because MSH_3 is not a valid Segment name