SafetyDataSheetAPI is a product of Dscvry. Explore Dscvry →

Reference

SDS to XML Converter API

Every extraction also comes back as XML. This page documents exactly how that XML is built, so your parser does not have to guess.

Last updated: 2026-10-24

The structure, by example

This is the XML for a small record (indented here for reading; the API returns it without whitespace between elements). It is the same data as outputs.json, with confidence_score and warnings added as final elements.

<?xml version="1.0" encoding="UTF-8"?>
<sds_extraction>
  <product_identification>
    <product_name>Acetone</product_name>
    <supplier_name>Example Chemicals</supplier_name>
  </product_identification>
  <hazards_identification>
    <ghs_classification>Flammable Liquid - Category 2</ghs_classification>
    <ghs_classification>Eye Irritation - Category 2A</ghs_classification>
    <signal_word>Danger</signal_word>
  </hazards_identification>
  <composition>
    <substance_name>Acetone</substance_name>
    <cas_number>67-64-1</cas_number>
    <concentration_percent>95-100</concentration_percent>
  </composition>
  <physical_chemical_properties>
    <flash_point_c>-20</flash_point_c>
    <odor></odor>
  </physical_chemical_properties>
  <transport_information>
    <un_number>UN1090</un_number>
    <hazard_class>3</hazard_class>
    <packing_group>II</packing_group>
  </transport_information>
  <confidence_score>0.94</confidence_score>
  <warnings>Section 9: boiling point unreadable</warnings>
</sds_extraction>

The rules

  • The root element is sds_extraction, and element names are the JSON keys, in the same order.
  • An array becomes repeated elements with the same name: two ghs_classification values give two ghs_classification elements.
  • An array of objects repeats the parent: each substance is its own composition element containing its fields.
  • A null or empty string becomes an empty element, such as <odor></odor>, and an empty array becomes one empty element.
  • There are no attributes and no namespaces. Values are XML-escaped (& < > and quotes).
  • Tag names are sanitized: spaces become underscores, characters outside letters, digits, _, . and - become underscores, and a name that does not start with a letter gets a leading underscore.
  • No XSD or DTD is published. The contract is the set of 16 section keys; fields inside a section follow the document.

Consequences to plan for

  • One item looks like a scalar. A list with one entry is a single element, the same as a plain value. Always read repeated elements with a find-all, never assume a count.
  • Empty is ambiguous. An empty element can mean null, an empty string or an empty array. If the difference matters, use the JSON output.
  • Confidence and warnings are in the document. In XML and CSV they are appended to the record. In the JSON response they are top-level fields beside outputs.

Parsing it

Python's standard library is enough. This snippet runs against a real response:

import xml.etree.ElementTree as ET

root = ET.fromstring(result["outputs"]["xml"])   # result = client.extract("sds.pdf")

un_number = root.findtext("transport_information/un_number")
confidence = float(root.findtext("confidence_score"))
warnings = [w.text for w in root.findall("warnings") if w.text]

# composition repeats once per substance, and a single substance is still one <composition>
substances = [{child.tag: child.text for child in item} for item in root.findall("composition")]
You wantPath (ElementTree)
UN numbertransport_information/un_number
All hazard classificationshazards_identification/ghs_classification (find-all)
Every substancecomposition (find-all, then read children)
Warningswarnings (find-all)

XML, JSON or CSV?

FormatChoose it whenWatch out for
JSONYou are building a new integration or need to tell null from empty.Inner field names follow the document, so map defensively.
XMLYour ERP, import tool or middleware expects XML.Single-item arrays look like scalars; empty elements are ambiguous.
CSVYou want a flat field,value list for a spreadsheet or quick review.See below.

How CSV is written

field,value
product_identification.product_name,Acetone
hazards_identification.ghs_classification,"[""Flammable Liquid - Category 2"",""Eye Irritation - Category 2A""]"
composition[0].substance_name,Acetone
composition[0].cas_number,67-64-1
physical_chemical_properties.flash_point_c,'-20
physical_chemical_properties.odor,
transport_information.un_number,UN1090
confidence_score,0.94
warnings,"[""Section 9: boiling point unreadable""]"
  • The header is field,value, with one row per value and dotted paths such as transport_information.un_number.
  • An array of objects is indexed, for example composition[0].cas_number. An array of plain values is written as a JSON string.
  • A value that starts with =, +, - or @ gets a leading apostrophe, which stops spreadsheets running it as a formula. That is why -20 appears as '-20: strip a leading apostrophe when you import numbers.

How you get access: the free sample upload on the homepage needs no key, the self-serve plan issues an API key after signup, and enterprise customers get a dedicated deployment with its own base URL. See pricing.

FAQ

Is there an XSD for the XML?

No schema file is published. Element names follow the JSON keys, and only the 16 section keys are part of the contract.

Does the XML include the confidence score and warnings?

Yes, as confidence_score and warnings elements at the end of the record.

Why does my one-item list parse as a single value?

Arrays are written as repeated elements, so a list of one is one element. Use a find-all and treat the result as a list.

Related pages

Want to see it on your own document? Try a sample SDS or request an implementation plan.