Task 487: .OSM File Format
Task 487: .OSM File Format
1. List of All Properties of the .OSM File Format Intrinsic to Its File System
The .OSM file format is an XML-based text format for OpenStreetMap data, with no binary headers or low-level file system-specific structures beyond standard XML encoding. "Intrinsic to its file system" refers to the core structural, metadata, and organizational properties that define how the data is stored and parsed on disk, such as the XML declaration, root attributes, and high-level metadata elements. These are self-contained within the file and do not rely on external file system metadata like timestamps or permissions. Based on the official specification, the key properties are:
- XML Version: The version of the XML standard used (typically "1.0").
- Encoding: The character encoding (always UTF-8 for .OSM files).
- OSM Version: The API version of the OSM data structure (e.g., "0.6").
- Generator: The name of the tool or software that generated the file (e.g., "JOSM" or "Overpass API").
- Bounds: The geographic bounding box, defined by attributes minlat (minimum latitude), minlon (minimum longitude), maxlat (maximum latitude), and maxlon (maximum longitude).
- Note: Optional text element providing licensing or source information (e.g., "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.").
- Meta osm_base: Optional attribute in a element indicating the base timestamp of the data (e.g., "2023-04-14T22:35:07Z").
These properties appear at the file's beginning and define the format's header-like structure. The rest of the file contains data elements (nodes, ways, relations), but those are not considered intrinsic properties of the format itself.
2. Two Direct Download Links for Files of Format .OSM
.OSM files are often distributed compressed (e.g., .osm.bz2) to reduce size, but they contain the raw .OSM XML format upon decompression. Here are two direct download links for small .OSM extracts:
- https://download.geofabrik.de/europe/monaco-latest.osm.bz2 (compressed .OSM XML for Monaco)
- https://download.geofabrik.de/europe/andorra-latest.osm.bz2 (compressed .OSM XML for Andorra)
3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .OSM File Dump
This is an embeddable HTML snippet with JavaScript for a Ghost blog. It creates a drop zone where users can drag and drop a .OSM file (or select via input). It uses the browser's FileReader and DOMParser to parse the XML and extract/dump the properties to the screen in a readable format.
4. Python Class for .OSM File Handling
This Python class uses xml.etree.ElementTree to open, parse (decode/read), print the properties, and write (save) the file (with optional modifications, e.g., updating the generator).
import xml.etree.ElementTree as ET
class OSMFileHandler:
def __init__(self, filepath):
self.filepath = filepath
self.tree = None
self.root = None
self.properties = {}
def read_and_decode(self):
self.tree = ET.parse(self.filepath)
self.root = self.tree.getroot()
bounds = self.root.find('bounds')
note = self.root.find('note')
meta = self.root.find('meta')
self.properties = {
'XML Version': '1.0', # Assumed, as ET doesn't expose it directly
'Encoding': 'UTF-8', # Assumed for .OSM
'OSM Version': self.root.attrib.get('version', 'N/A'),
'Generator': self.root.attrib.get('generator', 'N/A'),
'Bounds': {
'minlat': bounds.attrib.get('minlat', 'N/A') if bounds is not None else 'N/A',
'minlon': bounds.attrib.get('minlon', 'N/A') if bounds is not None else 'N/A',
'maxlat': bounds.attrib.get('maxlat', 'N/A') if bounds is not None else 'N/A',
'maxlon': bounds.attrib.get('maxlon', 'N/A') if bounds is not None else 'N/A'
} if bounds is not None else 'N/A',
'Note': note.text if note is not None else 'N/A',
'Meta osm_base': meta.attrib.get('osm_base', 'N/A') if meta is not None else 'N/A'
}
def print_properties(self):
if not self.properties:
print("No properties loaded. Call read_and_decode() first.")
return
print("OSM File Properties:")
for key, value in self.properties.items():
if isinstance(value, dict):
print(f"{key}:")
for subkey, subvalue in value.items():
print(f" {subkey}: {subvalue}")
else:
print(f"{key}: {value}")
def write(self, output_filepath=None, update_generator=None):
if not self.tree:
print("No data to write. Call read_and_decode() first.")
return
if update_generator:
self.root.set('generator', update_generator)
if output_filepath is None:
output_filepath = self.filepath
self.tree.write(output_filepath, encoding='utf-8', xml_declaration=True)
# Example usage:
# handler = OSMFileHandler('sample.osm')
# handler.read_and_decode()
# handler.print_properties()
# handler.write('output.osm', update_generator='Custom Generator')
5. Java Class for .OSM File Handling
This Java class uses javax.xml.parsers to parse, read, print properties, and write the file (with optional modification).
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.io.File;
public class OSMFileHandler {
private String filepath;
private Document doc;
private Element root;
public OSMFileHandler(String filepath) {
this.filepath = filepath;
}
public void readAndDecode() throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(new File(filepath));
root = doc.getDocumentElement();
System.out.println("OSM File Properties:");
System.out.println("XML Version: 1.0"); // Assumed
System.out.println("Encoding: UTF-8"); // Assumed
System.out.println("OSM Version: " + (root.getAttribute("version").isEmpty() ? "N/A" : root.getAttribute("version")));
System.out.println("Generator: " + (root.getAttribute("generator").isEmpty() ? "N/A" : root.getAttribute("generator")));
Node bounds = doc.getElementsByTagName("bounds").item(0);
if (bounds != null) {
Element boundsElem = (Element) bounds;
System.out.println("Bounds:");
System.out.println(" minlat: " + boundsElem.getAttribute("minlat"));
System.out.println(" minlon: " + boundsElem.getAttribute("minlon"));
System.out.println(" maxlat: " + boundsElem.getAttribute("maxlat"));
System.out.println(" maxlon: " + boundsElem.getAttribute("maxlon"));
} else {
System.out.println("Bounds: N/A");
}
Node note = doc.getElementsByTagName("note").item(0);
System.out.println("Note: " + (note != null ? note.getTextContent() : "N/A"));
Node meta = doc.getElementsByTagName("meta").item(0);
if (meta != null) {
Element metaElem = (Element) meta;
System.out.println("Meta osm_base: " + metaElem.getAttribute("osm_base"));
} else {
System.out.println("Meta osm_base: N/A");
}
}
public void write(String outputFilepath, String updateGenerator) throws Exception {
if (updateGenerator != null) {
root.setAttribute("generator", updateGenerator);
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(outputFilepath != null ? outputFilepath : filepath));
transformer.transform(source, result);
}
// Example usage:
// public static void main(String[] args) throws Exception {
// OSMFileHandler handler = new OSMFileHandler("sample.osm");
// handler.readAndDecode();
// handler.write("output.osm", "Custom Generator");
// }
}
6. JavaScript Class for .OSM File Handling
This JavaScript class uses DOMParser for browser environments to parse, read, print properties to console, and write (via Blob for download).
class OSMFileHandler {
constructor(filepath) {
this.filepath = filepath; // For Node, use fs; here assuming browser or adjust for Node.
this.xmlDoc = null;
}
async readAndDecode(fileContent) { // Pass content if from FileReader, or fetch if filepath.
const parser = new DOMParser();
this.xmlDoc = parser.parseFromString(fileContent, 'text/xml');
const root = this.xmlDoc.getElementsByTagName('osm')[0];
const bounds = this.xmlDoc.getElementsByTagName('bounds')[0];
const note = this.xmlDoc.getElementsByTagName('note')[0];
const meta = this.xmlDoc.getElementsByTagName('meta')[0];
console.log('OSM File Properties:');
console.log('XML Version:', this.xmlDoc.xmlVersion || '1.0');
console.log('Encoding:', this.xmlDoc.xmlEncoding || 'UTF-8');
console.log('OSM Version:', root ? root.getAttribute('version') : 'N/A');
console.log('Generator:', root ? root.getAttribute('generator') : 'N/A');
console.log('Bounds:', bounds ?
`minlat=${bounds.getAttribute('minlat')}, minlon=${bounds.getAttribute('minlon')}, maxlat=${bounds.getAttribute('maxlat')}, maxlon=${bounds.getAttribute('maxlon')}` : 'N/A');
console.log('Note:', note ? note.textContent : 'N/A');
console.log('Meta osm_base:', meta ? meta.getAttribute('osm_base') : 'N/A');
}
write(updateGenerator = null) {
if (!this.xmlDoc) {
console.error('No data to write. Call readAndDecode first.');
return;
}
if (updateGenerator) {
const root = this.xmlDoc.getElementsByTagName('osm')[0];
root.setAttribute('generator', updateGenerator);
}
const serializer = new XMLSerializer();
const xmlString = serializer.serializeToString(this.xmlDoc);
const blob = new Blob([xmlString], { type: 'application/xml' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'output.osm';
a.click();
URL.revokeObjectURL(url);
}
}
// Example usage (browser):
// const handler = new OSMFileHandler('sample.osm');
// fetch('sample.osm').then(res => res.text()).then(text => {
// handler.readAndDecode(text);
// handler.write('Custom Generator');
// });
7. C Class for .OSM File Handling
Assuming C++ (as "c class" likely means C++, since pure C lacks classes and built-in XML parsing). This uses <tinyxml2.h> (a common single-header library; include it externally). It opens, parses, prints properties, and writes the file.
#include <iostream>
#include <fstream>
#include <string>
#include "tinyxml2.h" // Assume tinyxml2 library is included.
using namespace tinyxml2;
class OSMFileHandler {
private:
std::string filepath;
XMLDocument doc;
public:
OSMFileHandler(const std::string& fp) : filepath(fp) {}
void readAndDecode() {
if (doc.LoadFile(filepath.c_str()) != XML_SUCCESS) {
std::cerr << "Failed to load file." << std::endl;
return;
}
XMLElement* root = doc.FirstChildElement("osm");
XMLElement* bounds = doc.FirstChildElement("bounds");
XMLElement* note = doc.FirstChildElement("note");
XMLElement* meta = doc.FirstChildElement("meta");
std::cout << "OSM File Properties:" << std::endl;
std::cout << "XML Version: 1.0" << std::endl; // Assumed
std::cout << "Encoding: UTF-8" << std::endl; // Assumed
std::cout << "OSM Version: " << (root ? root->Attribute("version") : "N/A") << std::endl;
std::cout << "Generator: " << (root ? root->Attribute("generator") : "N/A") << std::endl;
if (bounds) {
std::cout << "Bounds:" << std::endl;
std::cout << " minlat: " << bounds->Attribute("minlat") << std::endl;
std::cout << " minlon: " << bounds->Attribute("minlon") << std::endl;
std::cout << " maxlat: " << bounds->Attribute("maxlat") << std::endl;
std::cout << " maxlon: " << bounds->Attribute("maxlon") << std::endl;
} else {
std::cout << "Bounds: N/A" << std::endl;
}
std::cout << "Note: " << (note ? note->GetText() : "N/A") << std::endl;
std::cout << "Meta osm_base: " << (meta ? meta->Attribute("osm_base") : "N/A") << std::endl;
}
void write(const std::string& outputFilepath, const std::string& updateGenerator = "") {
XMLElement* root = doc.FirstChildElement("osm");
if (!root) {
std::cerr << "No data to write." << std::endl;
return;
}
if (!updateGenerator.empty()) {
root->SetAttribute("generator", updateGenerator.c_str());
}
doc.SaveFile(outputFilepath.empty() ? filepath.c_str() : outputFilepath.c_str());
}
};
// Example usage:
// int main() {
// OSMFileHandler handler("sample.osm");
// handler.readAndDecode();
// handler.write("output.osm", "Custom Generator");
// return 0;
// }