Task 337: .JVX File Format

Task 337: .JVX File Format

.JVX File Format Specifications

The .JVX file format is an XML-based geometry format used by JavaView, a 3D visualization software. It supports 2D and 3D objects represented as points, lines, polygons, and vector fields. The format includes metadata, descriptions, and geometric data, with validation via a DTD (Document Type Definition) available at http://www.javaview.de/rsrc/jvx.dtd. Files typically start with an XML declaration and reference the DTD. The structure is hierarchical, allowing multiple geometries per file.

1. List of Properties Intrinsic to the File Format

The properties are the XML elements, attributes, and text content defining the file's structure. Here's a comprehensive list based on the format's specification and DTD:

Root Element: <jvx-model>

  • No attributes.
  • Contains all other elements.

Metadata:

  • <meta>: Attributes - generator (string, e.g., "JavaView v.2.00"), date (string, e.g., "Thu Jan 18 00:10:21 GMT+01:00 2001").

Version:

  • <version>: Attribute - type (string, e.g., "final"). Text content: version number (e.g., "2.00").

Title:

  • <title>: No attributes. Text content: model title (string).

Authors:

  • <authors>: No attributes.
  • <author> (multiple): No attributes.
  • <firstname>: Text content: author's first name.
  • <lastname>: Text content: author's last name.
  • <affiliation>: No attributes.
  • <organization>: Text content: organization name.
  • <address>: No attributes.
  • <line> (multiple): Text content: address lines.
  • <email>: Text content: email address.
  • <url>: Text content: URL.

Description:

  • <description>: No attributes.
  • <abstract>: Text content: brief summary.
  • <detail>: Text content: detailed description.
  • <keywords>: No attributes.
  • <keyword> (multiple): Text content: keywords.
  • <msc2000>: No attributes.
  • <primary>: Text content: primary classification.
  • <secondary> (multiple): Text content: secondary classifications.
  • <software>: Text content: software used.

Geometries:

  • <geometries>: No attributes.
  • <geometry> (multiple): Attribute - name (string, e.g., "flux").
  • <pointSet>: Attributes - dim (integer, e.g., 3), point (string, "show" or "hide"), color (string, "show" or "hide").
  • <points>: No attributes.
  • <p> (multiple): Text content: space-separated coordinates (floats).
  • <thickness>: Text content: point thickness (integer).
  • <colors>: No attributes.
  • <c> (multiple): Text content: space-separated RGB values (0-255).
  • <normals> (optional): No attributes.
  • <n> (multiple): Text content: space-separated normal vectors.
  • <textures> (optional): Attributes - type (string), others for blending/filtering.
  • <t> (multiple): Text content: texture coordinates.
  • <vectorField> (multiple): Attributes - name (string), arrow (string, "show" or "hide"), base (string, e.g., "vertex").
  • <vectors>: No attributes.
  • <v> (multiple): Text content: space-separated vector components (floats).
  • <color>: Text content: space-separated RGB.
  • <thickness> (optional): Text content: thickness.
  • <material> (optional): Attributes for material properties (e.g., ambient, diffuse).
  • <lineSet>: Attribute - line (string, "show" or "hide").
  • <lines>: No attributes.
  • <l> (multiple): Text content: space-separated vertex indices (integers).
  • <colors> (optional): No attributes.
  • <c> (multiple): Text content: space-separated RGB.
  • <thickness>: Text content: line thickness.
  • <arrowStart> (optional): String for start arrow.
  • <faceSet>: Attributes - face (string, "show" or "hide"), edge (string, "show" or "hide").
  • <faces>: No attributes.
  • <f> (multiple): Text content: space-separated vertex indices (integers).
  • <colors> (optional): No attributes.
  • <c> (multiple): Text content: space-separated RGB.
  • <normals> (optional): No attributes.
  • <n> (multiple): Text content: space-separated normals.
  • <boundaries> (optional): Attributes for boundary drawing.
  • <neighbours> (optional): Attribute - num (integer). Text content: neighbor data.
  • <material> (optional): Attributes for shading (e.g., Gouraud, smooth).
  • <transformation> (optional): Matrix for transformations.
  • <material> (optional, global): Attributes for overall material (e.g., colorBackGlobal).

Additional properties from DTD include labels, animations, zentralblatt classification, and bounds for textures. The format supports forward compatibility since version 1.02.

3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .JVX File Dump

Here's an HTML page with embedded JavaScript that allows dragging and dropping a .JVX file. It reads the file as text, parses it as XML, extracts all properties (elements, attributes, text), and dumps them to the screen in a readable tree format.

JVX File Dumper
Drag and drop .JVX file here

4. Python Class for .JVX Handling

import xml.etree.ElementTree as ET
import os

class JVXHandler:
    def __init__(self, filepath):
        self.filepath = filepath
        self.tree = None
        self.root = None

    def read(self):
        try:
            self.tree = ET.parse(self.filepath)
            self.root = self.tree.getroot()
        except Exception as e:
            print(f"Error reading JVX: {e}")

    def print_properties(self):
        if not self.root:
            print("No JVX loaded.")
            return
        self._dump_element(self.root, 0)

    def _dump_element(self, element, indent):
        spaces = '  ' * indent
        attrs = ' '.join([f'{k}="{v}"' for k, v in element.attrib.items()])
        print(f"{spaces}<{element.tag} {attrs}>")
        if element.text and element.text.strip():
            print(f"{spaces}  {element.text.strip()}")
        for child in element:
            self._dump_element(child, indent + 1)
        print(f"{spaces}</{element.tag}>")

    def write(self, output_path):
        if not self.tree:
            # Create a sample tree if none loaded
            self.root = ET.Element('jvx-model')
            version = ET.SubElement(self.root, 'version', {'type': 'final'})
            version.text = '2.00'
            title = ET.SubElement(self.root, 'title')
            title.text = 'Sample JVX'
            self.tree = ET.ElementTree(self.root)
        try:
            self.tree.write(output_path, encoding='ISO-8859-1', xml_declaration=True)
            print(f"Written to {output_path}")
        except Exception as e:
            print(f"Error writing JVX: {e}")

# Example usage:
# handler = JVXHandler('sample.jvx')
# handler.read()
# handler.print_properties()
# handler.write('output.jvx')

5. Java Class for .JVX Handling

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 org.w3c.dom.NodeList;
import java.io.File;

public class JVXHandler {
    private String filepath;
    private Document doc;

    public JVXHandler(String filepath) {
        this.filepath = filepath;
    }

    public void read() {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            doc = builder.parse(new File(filepath));
            doc.getDocumentElement().normalize();
        } catch (Exception e) {
            System.out.println("Error reading JVX: " + e.getMessage());
        }
    }

    public void printProperties() {
        if (doc == null) {
            System.out.println("No JVX loaded.");
            return;
        }
        dumpNode(doc.getDocumentElement(), 0);
    }

    private void dumpNode(Node node, int indent) {
        String spaces = "  ".repeat(indent);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            Element elem = (Element) node;
            String attrs = "";
            for (int i = 0; i < elem.getAttributes().getLength(); i++) {
                attrs += " " + elem.getAttributes().item(i);
            }
            System.out.println(spaces + "<" + node.getNodeName() + attrs + ">");
            if (node.getTextContent() != null && !node.getTextContent().trim().isEmpty()) {
                System.out.println(spaces + "  " + node.getTextContent().trim());
            }
            NodeList children = node.getChildNodes();
            for (int i = 0; i < children.getLength(); i++) {
                dumpNode(children.item(i), indent + 1);
            }
            System.out.println(spaces + "</" + node.getNodeName() + ">");
        }
    }

    public void write(String outputPath) {
        try {
            if (doc == null) {
                // Create sample document
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                doc = builder.newDocument();
                Element root = doc.createElement("jvx-model");
                doc.appendChild(root);
                Element version = doc.createElement("version");
                version.setAttribute("type", "final");
                version.setTextContent("2.00");
                root.appendChild(version);
                Element title = doc.createElement("title");
                title.setTextContent("Sample JVX");
                root.appendChild(title);
            }
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(new File(outputPath));
            transformer.transform(source, result);
            System.out.println("Written to " + outputPath);
        } catch (Exception e) {
            System.out.println("Error writing JVX: " + e.getMessage());
        }
    }

    // Example usage:
    // public static void main(String[] args) {
    //     JVXHandler handler = new JVXHandler("sample.jvx");
    //     handler.read();
    //     handler.printProperties();
    //     handler.write("output.jvx");
    // }
}

6. JavaScript Class for .JVX Handling

This is for browser environment (uses DOMParser). For Node.js, use a library like xml2js.

class JVXHandler {
    constructor(filepath) {
        this.filepath = filepath; // For browser, filepath not used; use loadFromText instead.
        this.xmlDoc = null;
    }

    // Read from text (since JS can't directly open files; assume text is provided or use FileReader separately)
    loadFromText(xmlText) {
        const parser = new DOMParser();
        this.xmlDoc = parser.parseFromString(xmlText, 'application/xml');
        if (this.xmlDoc.getElementsByTagName('parsererror').length > 0) {
            console.log('Error parsing XML.');
            this.xmlDoc = null;
        }
    }

    printProperties() {
        if (!this.xmlDoc) {
            console.log('No JVX loaded.');
            return;
        }
        console.log(this.dumpNode(this.xmlDoc.documentElement, 0));
    }

    dumpNode(node, indent) {
        let result = '';
        const spaces = '  '.repeat(indent);
        result += `${spaces}<${node.tagName}`;
        for (let attr of node.attributes) {
            result += ` ${attr.name}="${attr.value}"`;
        }
        result += '>\n';
        if (node.textContent && node.textContent.trim()) {
            result += `${spaces}  ${node.textContent.trim()}\n`;
        }
        for (let child of node.children) {
            result += this.dumpNode(child, indent + 1);
        }
        result += `${spaces}</${node.tagName}>\n`;
        return result;
    }

    write() {
        if (!this.xmlDoc) {
            // Create sample
            const xmlText = `<?xml version="1.0" encoding="ISO-8859-1"?>
<jvx-model>
    <version type="final">2.00</version>
    <title>Sample JVX</title>
</jvx-model>`;
            this.loadFromText(xmlText);
        }
        const serializer = new XMLSerializer();
        const xmlStr = serializer.serializeToString(this.xmlDoc);
        console.log('Serialized JVX:\n' + xmlStr);
        // To save: Use Blob and URL.createObjectURL for download.
        const blob = new Blob([xmlStr], { type: 'application/xml' });
        const url = URL.createObjectURL(blob);
        console.log('Download link: ' + url);
        // Auto-download example: const a = document.createElement('a'); a.href = url; a.download = 'output.jvx'; a.click();
    }
}

// Example usage:
// const handler = new JVXHandler();
// handler.loadFromText('<jvx-model>...</jvx-model>'); // Replace with actual text
// handler.printProperties();
// handler.write();

7. C++ Class for .JVX Handling

This uses a simple manual parser for demonstration (since no external libraries assumed; in practice, use libxml2 or TinyXML). For full XML parsing, integrate a library. Here, it reads as string and prints raw structure (not full parse).

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>

class JVXHandler {
private:
    std::string filepath;
    std::string xmlContent;

    void dumpProperties(const std::string& content) {
        // Simple regex-based dumper for elements/attributes/text (not robust, for demo)
        std::regex elemRegex("<(\\w+)([^>]*)>(.*?)</\\1>", std::regex::dotall);
        std::smatch matches;
        std::string temp = content;
        while (std::regex_search(temp, matches, elemRegex)) {
            std::cout << "<" << matches[1] << matches[2] << ">" << std::endl;
            if (!matches[3].str().empty() && matches[3].str().find('<') == std::string::npos) {
                std::cout << "  " << matches[3] << std::endl;
            } else if (!matches[3].str().empty()) {
                dumpProperties(matches[3]); // Recurse for nested
            }
            std::cout << "</" << matches[1] << ">" << std::endl;
            temp = matches.suffix();
        }
    }

public:
    JVXHandler(const std::string& fp) : filepath(fp) {}

    void read() {
        std::ifstream file(filepath);
        if (!file.is_open()) {
            std::cout << "Error opening JVX file." << std::endl;
            return;
        }
        xmlContent.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();
    }

    void printProperties() {
        if (xmlContent.empty()) {
            std::cout << "No JVX loaded." << std::endl;
            return;
        }
        dumpProperties(xmlContent);
    }

    void write(const std::string& outputPath) {
        std::ofstream outFile(outputPath);
        if (!outFile.is_open()) {
            std::cout << "Error writing JVX." << std::endl;
            return;
        }
        if (xmlContent.empty()) {
            // Sample content
            xmlContent = R"(<?xml version="1.0" encoding="ISO-8859-1"?>
<jvx-model>
    <version type="final">2.00</version>
    <title>Sample JVX</title>
</jvx-model>)";
        }
        outFile << xmlContent;
        outFile.close();
        std::cout << "Written to " << outputPath << std::endl;
    }
};

// Example usage:
// int main() {
//     JVXHandler handler("sample.jvx");
//     handler.read();
//     handler.printProperties();
//     handler.write("output.jvx");
//     return 0;
// }