<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ json-schema - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ json-schema - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 25 Jul 2026 22:28:31 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/json-schema/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Transform JSON Data to Match Any Schema ]]>
                </title>
                <description>
                    <![CDATA[ Whether you’re transferring data between APIs or just preparing JSON data for import, mismatched schemas can break your workflow.  Learning how to clean and normalize JSON data ensures a smooth, error-free data transfer. This tutorial demonstrates ho... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/transform-json-data-schema/</link>
                <guid isPermaLink="false">686f40595293ca3e659585b7</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pandas ]]>
                    </category>
                
                    <category>
                        <![CDATA[ json ]]>
                    </category>
                
                    <category>
                        <![CDATA[ json-schema ]]>
                    </category>
                
                    <category>
                        <![CDATA[ python beginner ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Nneoma Uche ]]>
                </dc:creator>
                <pubDate>Thu, 10 Jul 2025 04:23:53 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752121420492/513db316-cdc7-47ef-8f20-4911cf5d41f9.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Whether you’re transferring data between APIs or just preparing JSON data for import, mismatched schemas can break your workflow.  Learning how to clean and normalize JSON data ensures a smooth, error-free data transfer.</p>
<p>This tutorial demonstrates how to clean messy JSON and export the results into a new file, based on a predefined schema. The JSON file we’ll be cleaning contains a dataset of 200 synthetic customer records.</p>
<p>In this tutorial, we’ll apply two methods for cleaning the input data:</p>
<ul>
<li><p>With pure Python</p>
</li>
<li><p>With <code>pandas</code></p>
</li>
</ul>
<p>You can apply either of these in your code. But the <code>pandas</code> method is better for large, complex data sets. Let’s jump right into the process.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-add-and-inspect-the-json-file">Add and Inspect the JSON File</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-define-the-target-schema">Define the Target Schema</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-clean-json-data-with-pure-python">How to Clean JSON Data with Pure Python</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-clean-json-data-with-pandas">How to Clean JSON Data with Pandas</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-validate-the-cleaned-json">How to Validate the Cleaned JSON</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-pandas-vs-pure-python-for-data-cleaning">Pandas vs Pure Python for Data Cleaning</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, you should have a basic understanding of:</p>
<ul>
<li><p>Python dictionaries, lists, and loops</p>
</li>
<li><p>JSON data structure (keys, values, and nesting)</p>
</li>
<li><p>How to read and write JSON files with Python’s <code>json</code> module</p>
</li>
</ul>
<h2 id="heading-add-and-inspect-the-json-file">Add and Inspect the JSON File</h2>
<p>Before you begin writing any code, make sure that the <strong>.json</strong> file you intend to clean is in your project directory. This makes it easy to load in your script using the file name alone.</p>
<p>You can now inspect the data structure by viewing the file locally or loading it in your script, with Python’s built-in <code>json</code> module.</p>
<p>Here’s how (assuming the file name is <strong>“old_customers.json”</strong>):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752079424973/3cd77410-6fa9-483d-9a73-edbe4c035327.jpeg" alt="Code to view or print contents of the raw JSON file in terminal" class="image--center mx-auto" width="407" height="231" loading="lazy"></p>
<p>This shows you whether the JSON file is structured as a dictionary or a list. It also prints out the entire file in your terminal. Mine is a dictionary that maps to a list of 200 customer entries. You should always open up the raw JSON file in your IDE to get a closer look at its structure and schema.</p>
<h2 id="heading-define-the-target-schema">Define the Target Schema</h2>
<p>If someone asks for JSON data to be cleaned, it probably means that the <a target="_blank" href="https://json-schema.org/understanding-json-schema/about">current schema</a> is unsuitable for its intended purpose. At this point, you want to be clear on what the final JSON export should look like.</p>
<p>JSON schema is essentially a blueprint that describes:</p>
<ul>
<li><p>required fields</p>
</li>
<li><p>field names</p>
</li>
<li><p>data type for each field</p>
</li>
<li><p>standardized formats (for example, lowercase emails, trimmed whitespace, etc.)</p>
</li>
</ul>
<p>Here’s what the old schema versus the target schema looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751956173106/d5957404-57ae-4de9-b61b-90eefa0b9260.jpeg" alt="A screenshot of the old JSON Schema to be transformed" class="image--center mx-auto" width="597" height="222" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751956365336/dcf6a024-1ae6-4c95-92ae-5544ba4cbb3e.jpeg" alt="The expected JSON Schema" class="image--center mx-auto" width="460" height="186" loading="lazy"></p>
<p>As you can see, the goal is to delete the <code>”customer_id”</code> and <code>”address”</code> fields in each entry and rename the rest from:</p>
<ul>
<li><p><code>”name”</code> to <code>”full_name”</code></p>
</li>
<li><p><code>”email”</code> to <code>”email_address”</code></p>
</li>
<li><p><code>”phone”</code> to <code>”mobile”</code></p>
</li>
<li><p><code>”membership_level”</code> to <code>”tier”</code></p>
</li>
</ul>
<p>The output should contain 4 response fields instead of 6, all renamed to fit the project requirements.</p>
<h2 id="heading-how-to-clean-json-data-with-pure-python">How to Clean JSON Data with Pure Python</h2>
<p>Let’s explore using Python’s built-in <code>json</code> module to align the raw data with the predefined schema.</p>
<h3 id="heading-step-1-import-json-and-time-modules">Step 1: Import <code>json</code> and <code>time</code> modules</h3>
<p>Importing <code>json</code> is necessary because we’re working with JSON files. But we’ll use the <code>time</code> module to track how long the data cleaning process takes.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> time
</code></pre>
<h3 id="heading-step-2-load-the-file-with-jsonload">Step 2: Load the file with <code>json.load()</code></h3>
<pre><code class="lang-python">start_time = time.time()
<span class="hljs-keyword">with</span> open(<span class="hljs-string">'old_customers.json'</span>) <span class="hljs-keyword">as</span> file:
    crm_data = json.load(file)
</code></pre>
<h3 id="heading-step-3-write-a-function-to-loop-through-and-clean-each-customer-entry-in-the-dictionary">Step 3: Write a function to loop through and clean each customer entry in the dictionary</h3>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">clean_data</span>(<span class="hljs-params">records</span>):</span>
    transformed_records = []
    <span class="hljs-keyword">for</span> customer <span class="hljs-keyword">in</span> records[<span class="hljs-string">"customers"</span>]:
        transformed_records.append({
                <span class="hljs-string">"full_name"</span>: customer[<span class="hljs-string">"name"</span>],
                <span class="hljs-string">"email_address"</span>: customer[<span class="hljs-string">"email"</span>],
                <span class="hljs-string">"mobile"</span>: customer[<span class="hljs-string">"phone"</span>],
                <span class="hljs-string">"tier"</span>: customer[<span class="hljs-string">"membership_level"</span>],

                })
    <span class="hljs-keyword">return</span> {<span class="hljs-string">"customers"</span>: transformed_records}

new_data = clean_data(crm_data)
</code></pre>
<p><code>clean_data()</code> takes in the original data (<strong>temporarily</strong>) stored in the records variable, transforming it to match our target schema.</p>
<p>Since the JSON file we loaded is a dictionary containing a <code>”customers”</code> key, which maps to a list of customer entries, we access this key and loop through each entry in the list.</p>
<p>In the for loop, we rename the relevant fields and store the cleaned entries in a new list called <code>”transformed_records”</code>.</p>
<p>Then, we return the dictionary, with the <code>”customers”</code> key intact.</p>
<h3 id="heading-step-4-save-the-output-in-a-json-file">Step 4: Save the output in a .json file</h3>
<p>Decide on a name for your cleaned JSON data and assign that to an <code>output_file</code> variable, like so:</p>
<pre><code class="lang-python">output_file = <span class="hljs-string">"transformed_data.json"</span>
<span class="hljs-keyword">with</span> open(output_file, <span class="hljs-string">"w"</span>) <span class="hljs-keyword">as</span> f:
    json.dump(new_data, f, indent=<span class="hljs-number">4</span>)
</code></pre>
<p>You can also add a <code>print()</code> statement below this block to confirm that the file has been saved in your project directory.</p>
<h3 id="heading-step-5-time-the-data-cleaning-process">Step 5: Time the data cleaning process</h3>
<p>At the beginning of this process, we imported the time module to measure how long it takes to clean up JSON data using pure Python. To track the runtime, we stored the current time in a <code>start_time</code> variable before the cleaning function, and we’ll now include an <code>end_time</code> variable at the end of the script.</p>
<p>The difference between the <code>end_time</code> and <code>start_time</code> values gives you the total runtime in seconds.</p>
<pre><code class="lang-python">end_time = time.time()
elapsed_time = end_time - start_time

print(<span class="hljs-string">f"Transformed data saved to <span class="hljs-subst">{output_file}</span>"</span>)
print(<span class="hljs-string">f"Processing data took <span class="hljs-subst">{elapsed_time:<span class="hljs-number">.2</span>f}</span> seconds"</span>)
</code></pre>
<p>Here’s how long the data cleaning process took with the pure Python approach:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751957367537/4a33fc16-7158-427e-b715-bec10a586857.jpeg" alt="Script runtime displayed in terminal" class="image--center mx-auto" width="766" height="88" loading="lazy"></p>
<h2 id="heading-how-to-clean-json-data-with-pandas">How to Clean JSON Data with Pandas</h2>
<p>Now we’re going to try achieving the same results as above, using Python and a third-party library called <code>pandas</code>. Pandas is an open-source library used for data manipulation and analysis in Python.</p>
<p>To get started, you need to have the Pandas library installed in your directory. In your terminal, run:</p>
<pre><code class="lang-python">pip install pandas
</code></pre>
<p>Then follow these steps:</p>
<h3 id="heading-step-1-import-the-relevant-libraries">Step 1: Import the relevant libraries</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
</code></pre>
<h3 id="heading-step-2-load-file-and-extract-customer-entries">Step 2: Load file and extract customer entries</h3>
<p>Unlike the pure Python method, where we simply indexed the key name <code>”customers”</code> to access the list of customer data, working with <code>pandas</code> requires a slightly different approach.</p>
<p>We must extract the list before loading it into a DataFrame because <code>pandas</code> expects structured data. Extracting the list of customer dictionaries upfront ensures that we isolate and clean the relevant records alone, preventing errors caused by nested or unrelated JSON data.</p>
<pre><code class="lang-python">start_time = time.time()
<span class="hljs-keyword">with</span> open(<span class="hljs-string">'old_customers.json'</span>, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> f:
    crm_data = json.load(f)

<span class="hljs-comment">#Extract the list of customer entries</span>
clients = crm_data.get(<span class="hljs-string">"customers"</span>, [])
</code></pre>
<h3 id="heading-step-3-load-customer-entries-into-a-dataframe">Step 3: Load customer entries into a DataFrame</h3>
<p>Once you’ve got a clean list of customer dictionaries, load the list into a DataFrame and assign said list to a variable, like so:</p>
<pre><code class="lang-python"><span class="hljs-comment">#Load into a dataframe</span>
df = pd.DataFrame(clients)
</code></pre>
<p>This creates a tabular or spreadsheet-like structure, where each row represents a customer. Loading the list into a DataFrame also allows you to access <code>pandas</code>’ powerful data cleaning methods like:</p>
<ul>
<li><p><code>drop_duplicate()</code>: removes duplicate rows or entries from a DataFrame</p>
</li>
<li><p><code>dropna()</code>: drops rows with any missing or null data</p>
</li>
<li><p><code>fillna(value)</code>: replaces all missing or null data with a specified value</p>
</li>
<li><p><code>drop(columns)</code>: drops unused columns explicitly</p>
</li>
</ul>
<h3 id="heading-step-4-write-a-custom-function-to-rename-relevant-fields">Step 4: Write a custom function to rename relevant fields</h3>
<p>At this point, we need a function that takes in a single customer entry – a row – and returns a cleaned version that fits the target schema (<code>“full_name”</code>, <code>“email_address”</code>, <code>“mobile”</code> and <code>“tier”</code>).</p>
<p>The function should also handle missing data by setting default values like <strong>”Unknown”</strong> or <strong>”N/A”</strong> when a field is absent.</p>
<p><strong>P.S:</strong> At first, I used <code>drop(columns)</code> to explicitly remove the <code>“address”</code> and <code>“customer_id”</code> fields. But it’s not needed in this case, as the <code>transform_fields()</code> function only selects and renames the required fields. Any extra columns are automatically excluded from the cleaned data.</p>
<h3 id="heading-step-5-apply-schema-transformation-to-all-rows">Step 5: Apply schema transformation to all rows</h3>
<p>We’ll use <code>pandas</code>' <code>apply()</code> method to apply our custom function to each row in the DataFrame. This will creates a Series (for example, 0 → {...}, 1 → {...}, 2 → {...}), which is not JSON-friendly.</p>
<p>As <code>json.dump()</code> expects a list, not a Pandas Series, we’ll apply <code>tolist()</code>, converting the Series to a list of dictionaries.</p>
<pre><code class="lang-python"><span class="hljs-comment">#Apply schema transformation to all rows</span>
transformed_df = df.apply(transform_fields, axis=<span class="hljs-number">1</span>)

<span class="hljs-comment">#Convert series to list of dicts</span>
transformed_data = transformed_df.tolist()
</code></pre>
<p>Another way to approach this is with list comprehension. Instead of using <code>apply()</code> at all, you can write:</p>
<pre><code class="lang-python">transformed_data = [transform_fields(row) <span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> df.to_dict(orient=<span class="hljs-string">"records"</span>)]
</code></pre>
<p><code>orient=”records”</code> is an argument for <code>df.to_dict</code> that tells pandas to convert the DataFrame to a list of dictionaries, where each dictionary represents a single customer record (that is, one row).</p>
<p>Then the <strong>for loop</strong> iterates through every customer record on the list, calling the custom function on each row. Finally, the list comprehension (<strong>[...]</strong>) collects the cleaned rows into a new list.</p>
<h3 id="heading-step-6-save-the-output-in-a-json-file">Step 6: Save the output in  a .json file</h3>
<pre><code class="lang-python"><span class="hljs-comment">#Save the cleaned data</span>
output_data = {<span class="hljs-string">"customers"</span>: transformed_data}
output_file = <span class="hljs-string">"applypandas_customer.json"</span>
<span class="hljs-keyword">with</span> open(output_file, <span class="hljs-string">"w"</span>) <span class="hljs-keyword">as</span> f:
    json.dump(output_data, f, indent=<span class="hljs-number">4</span>)
</code></pre>
<p>I recommend picking a different file name for your <code>pandas</code> output. You can inspect both files side by side to see if this output matches the result you got from cleaning with pure Python.</p>
<h3 id="heading-step-7-track-runtime">Step 7: Track runtime</h3>
<p>Once again, check for the difference between start time and end time to determine the program’s execution time.</p>
<pre><code class="lang-python">end_time = time.time()
elapsed_time = end_time - start_time

<span class="hljs-comment">#print(f"Transformed data saved to {output_file}")</span>
print(<span class="hljs-string">f"Transformed data saved to <span class="hljs-subst">{output_file}</span>"</span>)
print(<span class="hljs-string">f"Processing data took <span class="hljs-subst">{elapsed_time:<span class="hljs-number">.2</span>f}</span> seconds"</span>)
</code></pre>
<p>When I used <strong>list comprehension</strong> to apply the custom function, my script’s runtime was <strong>0.03 seconds</strong>, but with <code>pandas</code>’ <code>apply()</code> function, the total runtime dropped to <strong>0.01 seconds</strong>.</p>
<h3 id="heading-final-output-preview">Final output preview:</h3>
<p>If you followed this tutorial closely, your JSON output should look like this – whether you used the <code>pandas</code> method or the pure Python approach:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751961256627/d7b585f7-4585-4354-9fa7-a171adb31f90.jpeg" alt="The expected JSON output after schema transformation" class="image--center mx-auto" width="455" height="310" loading="lazy"></p>
<h2 id="heading-how-to-validate-the-cleaned-json">How to Validate the Cleaned JSON</h2>
<p>Validating your output ensures that the cleaned data follows the expected structure before being used or shared. This step helps to catch formatting errors, missing fields, and wrong data types early.</p>
<p>Below are the steps for validating your cleaned JSON file:</p>
<h3 id="heading-step-1-install-and-import-jsonschema">Step 1: Install and import <code>jsonschema</code></h3>
<p><code>jsonschema</code> is a third-party validation library for Python. It helps you define the expected structure of your JSON data and automatically check if your output matches that structure.</p>
<p>In your terminal, run:</p>
<pre><code class="lang-python">pip install jsonschema
</code></pre>
<p>Import the required libraries:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">from</span> jsonschema <span class="hljs-keyword">import</span> validate, ValidationError
</code></pre>
<p><code>validate()</code> checks whether your JSON data matches the rules defined in your schema. If the data is valid, nothing happens. But if there’s an error – like a missing field or wrong data type – it raises a <code>ValidationError</code>.</p>
<h3 id="heading-step-2-define-a-schema">Step 2: Define a schema</h3>
<p>As you know, JSON schema changes with each file structure. If your JSON data differs from what we’ve been working with so far, learn how to create a schema <a target="_blank" href="https://json-schema.org/learn/getting-started-step-by-step#validate-json-data-against-the-schema">here</a>. Otherwise, the schema below defines the structure we expect for our cleaned JSON:</p>
<pre><code class="lang-python">schema = {
    <span class="hljs-string">"type"</span>: <span class="hljs-string">"object"</span>,
    <span class="hljs-string">"properties"</span>: {
        <span class="hljs-string">"customers"</span>: {
            <span class="hljs-string">"type"</span>: <span class="hljs-string">"array"</span>,
            <span class="hljs-string">"items"</span>: {
                <span class="hljs-string">"type"</span>: <span class="hljs-string">"object"</span>,
                <span class="hljs-string">"properties"</span>: {
                    <span class="hljs-string">"full_name"</span>: {<span class="hljs-string">"type"</span>: <span class="hljs-string">"string"</span>},
                    <span class="hljs-string">"email_address"</span>: {<span class="hljs-string">"type"</span>: <span class="hljs-string">"string"</span>},
                    <span class="hljs-string">"mobile"</span>: {<span class="hljs-string">"type"</span>: <span class="hljs-string">"string"</span>},
                    <span class="hljs-string">"tier"</span>: {<span class="hljs-string">"type"</span>: <span class="hljs-string">"string"</span>}
                },
                <span class="hljs-string">"required"</span>: [<span class="hljs-string">"full_name"</span>, <span class="hljs-string">"email_address"</span>, <span class="hljs-string">"mobile"</span>, <span class="hljs-string">"tier"</span>]
            }
        }
    },
    <span class="hljs-string">"required"</span>: [<span class="hljs-string">"customers"</span>]
}
</code></pre>
<ul>
<li><p>The data is an object that must contain a key: <code>"customers"</code>.</p>
</li>
<li><p><code>"customers"</code> must be an <strong>array</strong> (a list), with each object representing one customer entry.</p>
</li>
<li><p>Each customer entry must have four fields–all strings:</p>
<ul>
<li><p><code>"full_name"</code></p>
</li>
<li><p><code>"email_address"</code></p>
</li>
<li><p><code>"mobile"</code></p>
</li>
<li><p><code>"tier"</code></p>
</li>
</ul>
</li>
<li><p>The <code>"required"</code> fields ensure that none of the relevant fields are missing in any customer record.</p>
</li>
</ul>
<h3 id="heading-step-3-load-the-cleaned-json-file">Step 3: Load the cleaned JSON file</h3>
<pre><code class="lang-python"><span class="hljs-keyword">with</span> open(<span class="hljs-string">"transformed_data.json"</span>) <span class="hljs-keyword">as</span> f:
    data = json.load(f)
</code></pre>
<h3 id="heading-step-4-validate-the-data">Step 4: Validate the data</h3>
<p>For this step, we’ll use a <code>try. . . except</code> block to end the process safely, and display a helpful message if the code raises a <code>ValidationError</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">try</span>:
    validate(instance=data, schema=schema)
    print(<span class="hljs-string">"JSON is valid."</span>)
<span class="hljs-keyword">except</span> ValidationError <span class="hljs-keyword">as</span> e:
    print(<span class="hljs-string">"JSON is invalid:"</span>, e.message)
</code></pre>
<h2 id="heading-pandas-vs-pure-python-for-data-cleaning">Pandas vs Pure Python for Data Cleaning</h2>
<p>From this tutorial, you can probably tell that using pure Python to clean and restructure JSON is the more straightforward approach. It is fast and ideal for handling small datasets or simple transformations.</p>
<p>But as data grows and becomes more complex, you might need advanced data cleaning methods that Python alone does not provide. In such cases, <code>pandas</code> becomes the better choice. It handles large, complex datasets effectively, providing built-in functions for handling missing data and removing duplicates.</p>
<p>You can study the <a target="_blank" href="https://pandas.pydata.org/Pandas_Cheat_Sheet.pdf">Pandas cheatsheet</a> to learn more data manipulation methods.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
