← All tasks
javacodex/java-t1 #3Not a task: already works

XML to JSON Converter (java, written by Codex)

envgap__codex__java-t1-3

Written by a coding agent; not on GitHubWritten 2026-03-02

01 / FAILURE SIGNATURE

As the study recorded it

None
Not a benchmark task.
  • The project already builds and runs before the fix, so there is nothing to repair.

02 / ENVIRONMENT RECIPE

Base commit
Not freshly verified
Manifest
pom.xml
Reproduce
Awaiting issue-specific recipe
Run under trace
Awaiting a meaningful runtime command

03 / TASK AND FAILURE

codex/java-t1 #3 · read the task the agent was given
Codex wrote this java project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written.

Task given to the agent:

TASK: XML to JSON Converter

Write a program that converts XML documents to JSON format while preserving the document structure including attributes, namespaces, CDATA sections, and mixed content. It should handle complex real-world XML with deeply nested elements.

FUNCTIONAL REQUIREMENTS:
- Accept an XML file path as a command-line argument
- Parse the full XML document including attributes, namespaces, text content, CDATA sections, and comments
- Convert to JSON preserving the hierarchy: elements become objects, repeated elements become arrays, attributes are prefixed with @ symbol, text content uses #text key
- Handle namespace prefixes by including them in key names
- Support converting multiple XML files in a directory via a --batch flag
- Print the resulting JSON to console with pretty-print formatting (indented)
- Save the output as a .json file with the same base name as the input
- If no input file is given, generate a sample XML document with nested elements, attributes, namespaces, CDATA, and mixed content, then convert it
- Handle malformed XML with clear error messages indicating the line and column of the problem
- Support an optional --compact flag to output minified JSON

Create a complete Java project for a clean Ubuntu 22.04 machine with only JDK 17+ installed. Include:
- Source code
- pom.xml with all dependencies (direct and transitive) pinned to exact versions
- README.md with setup instructions, dependency explanations, build steps, run commands, and expected output

04 / LABELS

Labels from the report text only; not yet run

No supported category has been assigned.

Label rules and the text that matched
[]

05 / FILES

The project as the agent wrote it

3 files, exactly as written, before any repair.

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>tmlr.codex_generated.p03</groupId>
  <artifactId>xml-to-json-converter</artifactId>
  <version>1.0.0</version>
  <name>XML to JSON Converter</name>
  <description>XML to JSON converter preserving attributes, namespaces, CDATA, comments, and mixed content.</description>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

  <dependencies>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.5.0</version>
        <configuration>
          <mainClass>XmlToJsonConverter</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
README.md
# XML to JSON Converter (Java)

Converts XML files to JSON while preserving nested structure, attributes, namespace prefixes, CDATA/text, comments, and mixed content.

## Features

- Accepts an XML file path as CLI input.
- Parses attributes, namespaces, text, CDATA, comments, and nested elements.
- Conversion rules:
  - attributes => `@attr`
  - text/CDATA => `#text`
  - comments => `#comment`
  - repeated elements => arrays
  - namespace prefixes preserved in keys
- `--batch` converts all `.xml` files in a directory.
- Pretty JSON output by default.
- `--compact` for minified JSON.
- Saves output as `<base>.json` next to input.
- If no file is provided, generates `sample.xml` and converts it.
- Malformed XML reports line and column.

## Requirements

- Ubuntu 22.04
- JDK 17+

## Dependencies (Pinned)

No external dependencies are used.

- Direct dependencies: none
- Transitive dependencies: none

`pom.xml` includes pinned Maven plugin versions.

## Build and Run

### JDK only

```bash
cd TMLR/code_generation/codex_generated/p_03/java
mkdir -p out
javac -d out src/main/java/XmlToJsonConverter.java
java -cp out XmlToJsonConverter ./input.xml
```

Batch mode:

```bash
java -cp out XmlToJsonConverter --batch ./xml_dir
```

Compact output:

```bash
java -cp out XmlToJsonConverter ./input.xml --compact
```

No args (generate sample):

```bash
java -cp out XmlToJsonConverter
```

### Maven

```bash
mvn -q compile
mvn -q exec:java -Dexec.args="./input.xml"
```
src/main/java/XmlToJsonConverter.java
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.xml.sax.InputSource;

public class XmlToJsonConverter {
    public static void main(String[] args) {
        try {
            int exitCode = run(args);
            System.exit(exitCode);
        } catch (Exception ex) {
            System.err.println("Unexpected failure: " + ex.getMessage());
            System.exit(1);
        }
    }

    private static int run(String[] args) throws IOException {
        boolean compact = false;
        boolean batch = false;
        List<String> paths = new ArrayList<>();

        for (String arg : args) {
            if ("--compact".equals(arg)) {
                compact = true;
            } else if ("--batch".equals(arg)) {
                batch = true;
            } else {
                paths.add(arg);
            }
        }

        if (batch) {
            if (paths.size() != 1) {
                System.err.println("Usage: java -cp out XmlToJsonConverter --batch <directory> [--compact]");
                return 1;
            }
            return convertBatch(paths.get(0), compact);
        }

        if (paths.isEmpty()) {
            Path samplePath = Paths.get("sample.xml").toAbsolutePath().normalize();
            Files.writeString(samplePath, sampleXml(), StandardCharsets.UTF_8);
            System.out.println("No input file provided. Generated sample XML: " + samplePath);
            return convertSingle(samplePath, compact);
        }

        if (paths.size() != 1) {
            System.err.println("Usage: java -cp out XmlToJsonConverter <file.xml> [--compact]");
            System.err.println("   or: java -cp out XmlToJsonConverter --batch <directory> [--compact]");
            return 1;
        }

        Path input = Paths.get(paths.get(0)).toAbsolutePath().normalize();
        return convertSingle(input, compact);
    }

    private static int convertBatch(String directory, boolean compact) throws IOException {
        Path dir = Paths.get(directory).toAbsolutePath().normalize();
        if (!Files.isDirectory(dir)) {
            System.err.println("Batch directory error: not a directory: " + dir);
            return 1;
        }

        List<Path> xmlFiles = new ArrayList<>();
        try (var stream = Files.list(dir)) {
            stream.filter(Files::isRegularFile)
                    .filter(path -> path.getFileName().toString().toLowerCase().endsWith(".xml"))
                    .forEach(xmlFiles::add);
        }
        Collections.sort(xmlFiles);

        if (xmlFiles.isEmpty()) {
            System.out.println("No XML files found in " + dir);
            return 0;
        }

        for (Path xmlFile : xmlFiles) {
            System.out.println("\n== " + xmlFile + " ==");
            int code = convertSingle(xmlFile, compact);
            if (code != 0) {
                return code;
            }
        }
        return 0;
    }

    private static int convertSingle(Path xmlFile, boolean compact) throws IOException {
        final String xmlText;
        try {
            xmlText = Files.readString(xmlFile, StandardCharsets.UTF_8);
        } catch (IOException ex) {
            System.err.println("File read error (" + xmlFile + "): " + ex.getMessage());
            return 1;
        }

        Document doc;
        try {
            doc = parseXml(xmlText);
        } catch (SAXParseException ex) {
            System.err.println("Malformed XML (" + xmlFile + "): " + ex.getMessage()
                    + " (line " + ex.getLineNumber() + ", column " + ex.getColumnNumber() + ")");
            return 1;
        } catch (SAXException | ParserConfigurationException ex) {
            System.err.println("XML parse error (" + xmlFile + "): " + ex.getMessage());
            return 1;
        }

        Element root = doc.getDocumentElement();
        Map<String, Object> converted = new LinkedHashMap<>();
        converted.put(root.getTagName(), elementToObject(root));

        String jsonText = compact ? JsonWriter.toJson(converted) : JsonWriter.toPrettyJson(converted);
        System.out.println(jsonText);

        Path outPath = xmlFile.resolveSibling(removeExtension(xmlFile.getFileName().toString()) + ".json");
        Files.writeString(outPath, jsonText + System.lineSeparator(), StandardCharsets.UTF_8);
        System.out.println("Saved: " + outPath.toAbsolutePath().normalize());
        return 0;
    }

    private static Document parseXml(String xmlText) throws ParserConfigurationException, IOException, SAXException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        factory.setIgnoringComments(false);
        factory.setCoalescing(false);
        factory.setExpandEntityReferences(false);

        DocumentBuilder builder = factory.newDocumentBuilder();
        InputSource source = new InputSource(new StringReader(xmlText));
        return builder.parse(source);
    }

    private static Map<String, Object> elementToObject(Element element) {
        Map<String, Object> result = new LinkedHashMap<>();

        NamedNodeMap attrs = element.getAttributes();
        for (int i = 0; i < attrs.getLength(); i++) {
            Node attr = attrs.item(i);
            result.put("@" + attr.getNodeName(), attr.getNodeValue());
        }

        Map<String, List<Object>> groupedChildren = new LinkedHashMap<>();
        List<String> textParts = new ArrayList<>();
        List<String> comments = new ArrayList<>();

        NodeList children = element.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node child = children.item(i);
            short type = child.getNodeType();

            if (type == Node.ELEMENT_NODE) {
                Element childElement = (Element) child;
                groupedChildren.computeIfAbsent(childElement.getTagName(), k -> new ArrayList<>())
                        .add(elementToObject(childElement));
            } else if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
                String text = child.getNodeValue();
                if (text != null && !text.trim().isEmpty()) {
                    textParts.add(text);
                }
            } else if (type == Node.COMMENT_NODE) {
                String value = ((Comment) child).getData();
                comments.add(value);
            }
        }

        for (Map.Entry<String, List<Object>> entry : groupedChildren.entrySet()) {
            if (entry.getValue().size() == 1) {
                result.put(entry.getKey(), entry.getValue().get(0));
            } else {
                result.put(entry.getKey(), entry.getValue());
            }
        }

        if (!textParts.isEmpty()) {
            result.put("#text", String.join(" ", textParts));
        }
        if (!comments.isEmpty()) {
            result.put("#comment", comments.size() == 1 ? comments.get(0) : comments);
        }

        return result;
    }

    private static String removeExtension(String fileName) {
        int idx = fileName.lastIndexOf('.');
        return idx <= 0 ? fileName : fileName.substring(0, idx);
    }

    private static String sampleXml() {
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<catalog xmlns:bk=\"http://example.com/book\" xmlns:meta=\"http://example.com/meta\" meta:version=\"1.2\">\n"
                + "  <!-- Inventory catalog -->\n"
                + "  <bk:book id=\"b1\" lang=\"en\">\n"
                + "    <bk:title>XML &amp; JSON Guide</bk:title>\n"
                + "    <bk:author>Jane Doe</bk:author>\n"
                + "    <bk:description><![CDATA[Great book with <examples> and mixed content]]></bk:description>\n"
                + "    <meta:note priority=\"high\">Read <meta:emphasis>carefully</meta:emphasis> now.</meta:note>\n"
                + "  </bk:book>\n"
                + "  <bk:book id=\"b2\" lang=\"fr\">\n"
                + "    <bk:title>Guide Avancé</bk:title>\n"
                + "    <bk:author>Jean Dupont</bk:author>\n"
                + "  </bk:book>\n"
                + "</catalog>\n";
    }

    private static final class JsonWriter {
        static String toJson(Object value) {
            StringBuilder sb = new StringBuilder();
            write(value, sb, false, 0);
            return sb.toString();
        }

        static String toPrettyJson(Object value) {
            StringBuilder sb = new StringBuilder();
            write(value, sb, true, 0);
            return sb.toString();
        }

        @SuppressWarnings("unchecked")
        private static void write(Object value, StringBuilder sb, boolean pretty, int indent) {
            if (value == null) {
                sb.append("null");
                return;
            }
            if (value instanceof String) {
                sb.append('"').append(escape((String) value)).append('"');
                return;
            }
            if (value instanceof Boolean || value instanceof Integer || value instanceof Long) {
                sb.append(value);
                return;
            }
            if (value instanceof Number) {
                double d = ((Number) value).doubleValue();
                if (Math.rint(d) == d) {
                    sb.append((long) d);
                } else {
                    sb.append(d);
                }
                return;
            }
            if (value instanceof List<?>) {
                List<Object> list = (List<Object>) value;
                sb.append('[');
                if (!list.isEmpty()) {
                    if (pretty) sb.append('\n');
                    for (int i = 0; i < list.size(); i++) {
                        if (pretty) indent(sb, indent + 1);
                        write(list.get(i), sb, pretty, indent + 1);
                        if (i < list.size() - 1) sb.append(',');
                        if (pretty) sb.append('\n');
                    }
                    if (pretty) indent(sb, indent);
                }
                sb.append(']');
                return;
            }
            if (value instanceof Map<?, ?>) {
                Map<String, Object> map = (Map<String, Object>) value;
                sb.append('{');
                if (!map.isEmpty()) {
                    if (pretty) sb.append('\n');
                    int i = 0;
                    for (Map.Entry<String, Object> entry : map.entrySet()) {
                        if (pretty) indent(sb, indent + 1);
                        sb.append('"').append(escape(entry.getKey())).append('"');
                        sb.append(pretty ? ": " : ":");
                        write(entry.getValue(), sb, pretty, indent + 1);
                        if (i < map.size() - 1) sb.append(',');
                        if (pretty) sb.append('\n');
                        i++;
                    }
                    if (pretty) indent(sb, indent);
                }
                sb.append('}');
                return;
            }
            sb.append('"').append(escape(String.valueOf(value))).append('"');
        }

        private static void indent(StringBuilder sb, int level) {
            for (int i = 0; i < level; i++) sb.append("  ");
        }

        private static String escape(String text) {
            StringBuilder out = new StringBuilder();
            for (int i = 0; i < text.length(); i++) {
                char ch = text.charAt(i);
                switch (ch) {
                    case '"':
                        out.append("\\\"");
                        break;
                    case '\\':
                        out.append("\\\\");
                        break;
                    case '\b':
                        out.append("\\b");
                        break;
                    case '\f':
                        out.append("\\f");
                        break;
                    case '\n':
                        out.append("\\n");
                        break;
                    case '\r':
                        out.append("\\r");
                        break;
                    case '\t':
                        out.append("\\t");
                        break;
                    default:
                        if (ch < 0x20) {
                            out.append(String.format("\\u%04x", (int) ch));
                        } else {
                            out.append(ch);
                        }
                }
            }
            return out.toString();
        }
    }
}