Closed Sue1990 closed 3 years ago
Your code is incorrect; there is some sleight-of-hand in the API which may have tripped you up. The problem is that obs.event.actions.action
evaluates to a list (a TypedList actually). Therefore obs.event.actions.action.description = ...
is assigning a value to an attribute of the list. What you meant to do is assign a value to an attribute of an element of the list. It is deceiving because obs.event.actions.action = Action()
is sneakily converting your single Action instance to a length-one list (of Action's).
So here are some options:
obs = Observable()
obs.event = Event()
obs.event.actions = Actions()
obs.event.actions.action = Action()
obs.event.actions.action[0].description = StructuredText(value="test")
This assigns a value to the description
attribute of the first list element (the first Action).
obs = Observable()
obs.event = Event()
obs.event.actions = Actions()
obs.event.actions.action = Action()
obs.event.actions[0].description = StructuredText(value="test")
This uses more sleight-of-hand in the API: Actions is an EntityList, and using it like a list actually "reads through" to its single list-valued attribute, which is action
. This makes it read a bit better, but is layering on more cleverness (which may be more of a bad thing!). You could explicitly assign a list to .action
to make it clearer that its value is a list:
obs.event.actions.action = [Action()]
or use that EntityList cleverness to treat .actions
more like a list and append a new Action to it using a normal list method:
obs.event.actions.append(Action())
Use whatever you think would cause the least misunderstanding in the future.
@chisholm thanks your help
@chisholm I have already used this (obs.event.actions.action[0].description = StructuredText(value="test")) method to resolved my problem , but when I do below down script it doesn't work again .
script : obs.event.actions.action[0].associated_objects = AssociatedObjects() obs.event.actions.action[0].associated_objects.associated_object = AssociatedObject() obs.event.actions.action[0].associated_objects.associated_object = NetworkConnection() obs.event.actions.action[0].associated_objects.associated_object.source_socket_address = SocketAddress() obs.event.actions.action[0].associated_objects.associated_object.source_socket_address.ip_address = Address() obs.event.actions.action[0].associated_objects.associated_object.source_socket_address.ip_address.address_value = String("127.0.0.1")
how can I identify AssociatedObject() method ? , I want to XML like below down picture:
Did I miss which method?
Your first problem is exactly the same as before. The .associated_object
attribute is list valued. You must treat it as a list!
Secondly, your code snip is confused. It assigns two different values to the same attribute:
.associated_object = AssociatedObject()
.associated_object = NetworkConnection()
That can't be right. I think you want:
.associated_object = AssociatedObject()
.associated_object[0].properties = NetworkConnection()
Altogether:
obs.event.actions.action[0].associated_objects = AssociatedObjects()
obs.event.actions.action[0].associated_objects.associated_object = AssociatedObject()
obs.event.actions.action[0].associated_objects.associated_object[0].properties = NetworkConnection()
obs.event.actions.action[0].associated_objects.associated_object[0].properties.source_socket_address = SocketAddress()
obs.event.actions.action[0].associated_objects.associated_object[0].properties.source_socket_address.ip_address = Address()
obs.event.actions.action[0].associated_objects.associated_object[0].properties.source_socket_address.ip_address.address_value = String("127.0.0.1")
@chisholm so, below down picture described "Currently only supports the id, association_type, and ObjectProperties properties", It means I not only can " association_type " (which has a gray background ) but also can use id and properties right?
This ObjectPropertiesType is in the STIX website described "Through this extension mechanism any object instance data based on an object properties schema extended from ObjectPropertiesType (e.g. File_Object, Address_Object, etc.) can be directly integrated into any instance document where a field is defined as ObjectPropertiesType."
and if the website marked "Bases: mixbox.entities.EntityList" ,Does it mean I must treat it as a list?
@chisholm so, below down picture described "Currently only supports the id, association_type, and ObjectProperties properties", It means I not only can " association_type " (which has a gray background ) but also can use id and properties right?
Yes. Actually, API-wise, AssociatedObject extends Object and therefore inherits all its attributes. That means for example:
obs.event.actions.action[0].associated_objects.associated_object[0].description = StructuredText("test")
works to add a description even though those docs say that only id
, association_type
, properties
are supported. Not sure in what sense those docs mean that other attributes are not supported (I am not the original author, and it's been a long time since I worked on this library!). The XML schema also defines AssociatedObjectType as an extension of ObjectType, which means it's schema-valid to use elements of ObjectType.
and if the website marked "Bases: mixbox.entities.EntityList" ,Does it mean I must treat it as a list?
No. EntityList is a convenience (sub)class which allows a list-like usage if desired. As far as I recall, you typically see it used in situations like:
<plural_noun>
<singular_noun>...</singular_noun>
<singular_noun>...</singular_noun>
etc...
</plural_noun>
This XML design style where you have a "container" XML element named after a pluralized version of the thing it contains seems to be a pretty common pattern. Imagine the plural_noun
XML element maps to a PluralNoun
class, and singular_noun
maps to a SingularNoun
class. The PluralNoun
class can be designed to subclass EntityList
, so you can treat its instances as lists of SingularNoun
instances. It would have a singular_noun
list-valued attribute which you can also use as my_plural_noun_instance.singular_noun[0]
if you wish, but my_plural_noun_instance[0]
is shorter and reads better (at least, I'm sure that was the intent). There is a lot of cleverness in the library (in fact, I think there's too much) which I'm sure was intended to make it easier to use, but which can paradoxically have the opposite effect and make for subtle stumbling blocks which are hard to understand.
So what I was referring to regarding the .associated_object
attribute is the multiple
parameter here:
That turns it into a list-valued attribute. If you use attribute like that, (a) understand that if you assign a non-list to it, it will be converted to a length-one list, and (b) if you read the value of the attribute, you will get a list. So you must work with it as such. The readthedocs link for that attribute is here, but you don't see that multiple
parameter there. It does say
(List of values permitted)
So at least there's that "list" hint. In general, where you see the XML container-element style, you tend to see EntityList
. Where you see repeated XML elements (even with no container), you see multiple=True
on the attribute. When there is repetition, the schema is not consistent about how it achieves that. Sometimes there is a container element and sometimes not. I was told that as the schema evolved, repetition was sometimes added where it was not allowed before, and adding a container element would break backward compatibility. So it was not done that way in those cases. But that results in an inconsistent schema design. Maybe the lesson here is that if you expect the schema to evolve and want backward compatibility while maintaining a consistent design style, "container" elements are a bad idea!
@chisholm Thanks for your explanation
@chisholm I followed your answers : obs.event.actions.action[0].associated_objects = AssociatedObjects() obs.event.actions.action[0].associated_objects.associated_object = AssociatedObject() obs.event.actions.action[0].associated_objects.associated_object[0].properties = NetworkConnection() obs.event.actions.action[0].associated_objects.associated_object[0].properties.source_socket_address = SocketAddress() obs.event.actions.action[0].associated_objects.associated_object[0].properties.source_socket_address.ip_address = Address() obs.event.actions.action[0].associated_objects.associated_object[0].properties.source_socket_address.ip_address.address_value = String("127.0.0.1")
and (List of values permitted) about .associated_object[0] . but it only for [0] , I can't type into [1] right ?
I tried to use .associated_object[1].properties = NetworkConnection() to have second NetworkConnectionObj in the same
If you have two associated objects, you could assign both with:
obs.event.actions.action[0].associated_objects.associated_object = [obj1, obj2]
If you are dealing with an existing AssociatedObjects
instance, you can append an additional associated object with:
obs.event.actions.action[0].associated_objects.associated_object.append(obj2)
You can assign or append as many as you need. You can get the number of associated objects via the len()
function:
len(obs.event.actions.action[0].associated_objects.associated_object)
It is your responsibility to make sure you don't try to access list elements which don't exist (i.e. out-of-bounds indices). See the Python reference documentation here and here for information about list APIs. For more tutorial information, see their tutorial sections here and here.
I tried to figure out the below down xml format
my script is : obs = Observable() obs.event = Event() obs.event.actions = Actions() obs.event.actions.action = Action() obs.event.actions.action.description = StructuredText(value="test")
why it doesn't show a description? is that a bug?