Version: 1.2.0
Example Code¶
The following sections demonstrate how to use the stix-ramrod library to update STIX content. For more details about the stix-ramrod API, see the API Documentation page.
Import stix-ramrod¶
To use stix-ramrod for updating STIX and CybOX content, you must import
the ramrod
module There are lots of functions, classes, and submodules
under ramrod
, but the top-level module is all you need for most updates!
import ramrod # That's it!
Calling the ramrod.update() Function¶
Once the imports are taken care of you only need to call the
ramrod.update()
method, which parses the content, updates it, and
returns an instance of UpdateResults
.
import ramrod
# Update the 'stix-content.xml' STIX document.
updated = ramrod.update('stix-content.xml')
Note
The example above passes the stix-content.xml
filename into
ramrod.update()
, but ramrod.update()
accepts file-like objects
(such as files on disk or StringIO
instances), etree._Element
instances, or etree._ElementTree
instances. Neato!
Retrieving Updated Content¶
After successfully calling ramrod.update()
, the update document can be
retrieved from the returned UpdateResults
object instance via
the document
attribute. The document
attribute is an instance of
ResultDocument
.
import ramrod
from lxml import etree # Used for printing the updated XML document
# Update the document
updated = ramrod.update('stix-content.xml')
# Print the resulting document to stdout
print updated
# Retrieve the updated document from the returned UpdateResults object
new_stix_doc = updated.document
# Or retrieve the etree._Element root
root = new_stix_doc.as_element()
Forcing An Update¶
Sometimes an update doesn’t go smoothly and a UpdateError
is raised because untranslatable data or non-unique IDs are discovered in the
source document. The following code and output demonstrates how to force the
update and retrieve the data that is lost in the process.
import ramrod
# Attempt to update an untranslatable document
updated = ramrod.update('untranslatable-stix-content.xml')
The untranslatable-stix-content.xml
contains untranslatable data, so a
UpdateError
gets raised:
ramrod.errors.UpdateError: Update Error: Found untranslatable fields in source document.
To find out exactly what couldn’t be translated, you can inspect the
disallowed
and duplicates
attributes on the UpdateError
instance:
import ramrod
import ramrod.errors # stix-ramrod error module
try:
# Attempt to update an untranslatable document
updated = ramrod.update('untranslatable-stix-content.xml')
except ramrod.errors.UpdateError as ex:
# Print untranslatable items
for node in ex.disallowed:
print "TAG: %s, LINE: %s" % (node.tag, node.sourceline) # etree API
# Print non-unique IDs and each line they're found on
for id_, nodes in ex.duplicates.iteritems():
print "ID: %s, LINES: %s" % (id_, [x.sourceline for x in nodes])
To force the update, pass in force=True
to the ramrod.update()
method:
import ramrod
# Force-update the document
updated = ramrod.update('untranslatable-stix-content.xml', force=True)
After successfully force-updating the document, items that had IDs remapped
or that were lost in translation can be retrieved from the returned
UpdateResults
object instance.
import ramrod
# Force-update the document
updated = ramrod.update('untranslatable-stix-content.xml', force=True)
# Iterate over the items which were lost in translation
for node in updated.removed:
do_something_with_the_removed_item(node)
# Iterate over the {id: [nodes]} dictionary containing nodes
# with remapped IDs
for original_id, node_list in updated.remapped_ids.iteritems():
do_something_with_remapped_items(original_id, node_list)
Using the UpdateOptions Class¶
Instances of the UpdateOptions
class can be passed into the
ramrod.update()
method to tweak what gets updated in a STIX or CybOX
document.
The following example shows how to use the UpdateOptions
class
to let the update code know not to update controlled vocabulary instances:
import ramrod
from lxml import etree # used for parsing XML
# Create the UpdateOptions instance
options = ramrod.UpdateOptions()
options.update_vocabularies = False # Don't Update Vocabs!
# Update the content
updated = ramrod.update('stix-content.xml', options=options)
# Print the results!
print updated
Working with python-stix¶
The python-stix library provides an API for developing and consuming STIX content. The python-stix library is designed to consume and produce specific versions of STIX, as detailed here.
Because python-stix consumes specific versions of STIX content, older content needs to be updated before it can be parsed. Luckily, updating old versions of STIX content is easy with stix-ramrod!
Example¶
The following example demonstrates one way of updating content so that python-stix can parse it. This code works with python-stix v1.1.1.1.
import ramrod
from stix.core import STIXPackage
from stix.utils.parser import UnsupportedVersionError
stix_filename = "stix-upgradable-content.xml"
try:
package = STIXPackage.from_xml(stix_filename)
except UnsupportedVersionError as ex:
updated = ramrod.update(stix_filename)
document = updated.document.as_stringio()
package = STIXPackage.from_xml(document)
# Work with the parsed STIXPackage instance.
print package.id_
Note
The example above assumes that the input content can be upgraded without
raising a UpdateError
or any other exceptions.