How To Read An Xml File In Python

6 min read

XML files are self‑describing data containers that store hierarchical information in a plain‑text format. When you need to extract values, validate structures, or integrate external data into a Python application, reading an XML file is a fundamental skill. This guide walks you through the most common techniques, explains the underlying concepts, and provides practical code examples that you can adapt to any project.

Introduction

Understanding how to read an XML file in Python empowers you to work with configuration files, web services, office documents, and many other data sources that rely on XML. The language’s standard library includes several strong parsers, and third‑party packages such as lxml extend functionality. By the end of this article you will know:

  • Which modules to import for simple versus advanced parsing.
  • How to deal with the XML tree, select nodes, and retrieve attributes.
  • Best practices for handling large files and avoiding common pitfalls.

Prerequisites

Before you begin, ensure you have a recent version of Python (3.Day to day, 7+ recommended). So naturally, no external installation is required for the built‑in **xml. etree.

pip install lxml

Using the built‑in xml.etree.ElementTree

Loading the file

The first step is to open the XML file and parse its contents. ElementTree provides a straightforward API:

import xml.etree.ElementTree as ET

tree = ET.Still, parse('data. xml')          # creates an ElementTree object
root = tree.

* **`ET.parse()`** reads the file and builds an in‑memory tree structure.  
* **`getroot()`** returns the top‑level element, which serves as the entry point for traversal.

### Basic navigation

Once you have the root element, you can explore the hierarchy using methods such as **`find()`**, **`findall()`**, and **`iter()`**. These methods accept XPath‑like expressions to locate specific nodes.

```python
# Find the first  element under 
first_book = root.find('library/book')
print(first_book.tag)   # 
  • tag refers to the element’s name (e.g., book).
  • find() returns a single matching element or None if not found.
  • findall() returns a list of all matching elements.

Accessing text and attributes

Elements store text content in the text attribute, while attributes are accessed via attrib, a dictionary‑like object.

book = root.find('.//book')          # locate any  element in the tree
title = book.find('title').text      # extract the text inside 
price_attr = book.attrib['price']    # read the "price" attribute
print(title, price_attr)
</code></pre>
<ul>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu"><code class="cw pn po pp pf b">text</code></strong> holds the character data between opening and closing tags.</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu"><code class="cw pn po pp pf b">attrib</code></strong> behaves like a Python dict, allowing you to read or modify attributes.</li>
</ul>
<h3 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Iterating over child elements</h3>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">When you need to process every child node, <strong class="na gu"><code class="cw pn po pp pf b">iter()</code></strong> or <strong class="na gu"><code class="cw pn po pp pf b">iterfind()</code></strong> are useful:</p>
<pre class="oz pa pb pc pd pe pf bo ph ba bj"><code class="hljs">for child in root.iter():
    if child.tag == 'author':
        print(child.text.strip())
</code></pre>
<h2 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Advanced parsing with lxml</h2>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">If you require better performance, support for namespaces, or full XPath queries, <strong class="na gu">lxml</strong> is the preferred choice That's the part that actually makes a difference..</p>
<h3 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Installing and importing</h3>
<pre class="oz pa pb pc pd pe pf bo ph ba bj"><code class="hljs">pip install lxml
</code></pre>
<pre class="oz pa pb pc pd pe pf bo ph ba bj"><code class="hljs">from lxml import etree
</code></pre>
<h3 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Parsing and XPath queries</h3>
<pre class="oz pa pb pc pd pe pf bo ph ba bj"><code class="hljs">parser = etree.XMLParser(remove_blank_text=True)
tree = etree.parse('data.xml', parser)
root = tree.getroot()

# XPath example: select all book titles
titles = root.xpath('//book/title/text()')
for t in titles:
    print(t)
</code></pre>
<ul>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu"><code class="cw pn po pp pf b">etree.parse()</code></strong> reads the file directly into an <strong class="na gu">lxml</strong> element tree.</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu"><code class="cw pn po pp pf b">xpath()</code></strong> enables concise selection using XPath expressions, which is especially handy for complex documents.</li>
</ul>
<h3 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Modifying and saving</h3>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">lxml also allows you to edit the XML in memory and write the changes back to a file:</p>
<pre class="oz pa pb pc pd pe pf bo ph ba bj"><code class="hljs">new_price = '29.99'
for book in root.xpath('//book'):
    book.set('price', new_price)

etree.dump(tree)   # prints the updated XML to stdout
</code></pre>
<h2 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Scientific Explanation</h2>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">XML is built on the concept of a <strong class="na gu">tree</strong>, where each node represents an element, attribute, or text node. Parsers transform the flat text into this hierarchical structure, enabling random access to any part of the document. The <strong class="na gu">ElementTree</strong> model mirrors the XML specification’s “one‑root‑element” rule, while <strong class="na gu">lxml</strong> extends it with a more flexible tree representation that supports additional node types and namespaces Not complicated — just consistent..</p>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">Understanding the tree model helps you avoid common errors such as:</p>
<ul>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Assuming a single root element</strong> when the file contains multiple top‑level elements (which is invalid XML).</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Neglecting namespaces</strong>, which can cause XPath queries to miss nodes.</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Reading the entire file into memory</strong> for very large files; in such cases, consider iterative parsing (e.g., <code class="cw pn po pp pf b">iterparse</code> in ElementTree).</li>
</ul>
<h2 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Step‑by‑step guide to reading an XML file</h2>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">Below is a concise workflow you can follow for most use cases:</p>
<ol>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Import the appropriate module</strong> (<code class="cw pn po pp pf b">xml.etree.ElementTree</code> for simple tasks, <code class="cw pn po pp pf b">lxml.etree</code> for advanced needs).</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Parse the file</strong> into a tree object (<code class="cw pn po pp pf b">ET.parse()</code> or <code class="cw pn po pp pf b">etree.parse()</code>).</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Obtain the root element</strong> (<code class="cw pn po pp pf b">tree.getroot()</code> or <code class="cw pn po pp pf b">tree.getroot()</code>).</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">manage the tree</strong> using <code class="cw pn po pp pf b">find()</code>, <code class="cw pn po pp pf b">findall()</code>, <code class="cw pn po pp pf b">iter()</code>, or XPath (<code class="cw pn po pp pf b">xpath()</code>).</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Extract data</strong> from <code class="cw pn po pp pf b">.text</code>, <code class="cw pn po pp pf b">.attrib</code>, or nested elements.</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Optional: iterate</strong> over nodes to process large datasets efficiently.</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Save changes</strong> (if needed) with <code class="cw pn po pp pf b">tree.write()</code> or <code class="cw pn po pp pf b">etree.tostring()</code>.</li>
</ol>
<h3 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Example: reading a library catalog</h3>
<pre class="oz pa pb pc pd pe pf bo ph ba bj"><code class="hljs">import xml.etree.ElementTree as ET

# 1. Parse the XML file
tree = ET.parse('library.xml')
root = tree.getroot()

# 2. Find all book elements
books = root.findall('book')

# 3. Iterate and print title + price
for b in books:
    title = b.find('title').text
    price = b.attrib.get('price', 'N/A')
    print(f"Title: {title}, Price: {price}")
</code></pre>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">This script demonstrates each step, from loading the file to extracting specific information.</p>
<h2 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Common scenarios and tips</h2>
<ul>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Reading large files</strong> – Use <code class="cw pn po pp pf b">iterparse()</code> to process the file incrementally, reducing memory usage:</p>
<pre class="oz pa pb pc pd pe pf bo ph ba bj"><code class="hljs">for event, elem in ET.Day to day, iterparse('large. Day to day, xml'):
    if elem. tag == 'record':
        # process elem
        elem.

</code></pre>
</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Handling namespaces</strong> – Register a namespace prefix before using XPath:</p>
<pre class="oz pa pb pc pd pe pf bo ph ba bj"><code class="hljs">ns = {'ns': 'http://example.com/ns'}
titles = root.xpath('//ns:book/ns:title/text()', namespaces=ns)
</code></pre>
</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Dealing with mixed content</strong> – When an element contains both text and child elements, the text may appear in the element’s <code class="cw pn po pp pf b">.text</code> attribute before the first child and after the last child. Use <code class="cw pn po pp pf b">elem.text</code> and <code class="cw pn po pp pf b">elem.tail</code> to capture all content Easy to understand, harder to ignore..</p>
</li>
<li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Validating XML</strong> – Before parsing, you can validate the file against an XSD schema using <code class="cw pn po pp pf b">lxml.etree.XMLSchema</code>. This ensures the structure you expect actually exists.</p>
</li>
</ul>
<h2 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">FAQ</h2>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Q1: Can I read XML from a string instead of a file?</strong><br>
Yes. Both modules accept a string via <code class="cw pn po pp pf b">ET.fromstring()</code> (ElementTree) or <code class="cw pn po pp pf b">etree.fromstring()</code> (lxml). This is useful for testing small snippets Practical, not theoretical..</p>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Q2: What if the XML uses a default namespace?</strong><br>
Default namespaces must be bound to a prefix manually, as XPath does not match them directly. Register the prefix in a dictionary and use it in your queries.</p>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Q3: How do I handle attributes that are not present?</strong><br>
Use the <code class="cw pn po pp pf b">.get()</code> method with a default value, e.g., <code class="cw pn po pp pf b">elem.attrib.get('price', '0')</code>. This prevents a <code class="cw pn po pp pf b">KeyError</code>.</p>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Q4: Is there a performance difference between ElementTree and lxml?</strong><br>
lxml is generally faster and more memory‑efficient, especially for large documents, because it is implemented in C and supports incremental parsing Turns out it matters..</p>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj"><strong class="na gu">Q5: Can I modify the XML while reading it?</strong><br>
Yes. Both parsers provide methods to set attributes (<code class="cw pn po pp pf b">elem.set()</code>) or insert new elements (<code class="cw pn po pp pf b">elem.append()</code>). Just remember to write the changes back to a file if persistence is required Small thing, real impact. Surprisingly effective..</p>
<h2 class="nw nx gt be ny nz oa ob oc od oe of og oh oi oj ok ol om on oo op oq or os ot bj">Conclusion</h2>
<p class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj">Reading an XML file in Python is a straightforward process once you understand the underlying tree model and the available parsing tools. etree.ElementTree** for quick scripts or <strong class="na gu">lxml</strong> for dependable, high‑performance applications, the steps remain consistent: parse the file, obtain the root, work through the hierarchy, and extract the needed data. Whether you use the built‑in **xml.By following the guidelines and examples presented here, you can confidently incorporate XML handling into your Python projects, unlocking the wealth of structured data that XML files provide And that's really what it comes down to. Less friction, more output..</p>
</div>
      </div>

      <!-- ═══ LATEST POSTS — struktur SAMA persis dengan template asli ═══ -->
      <section class="post-section" id="sec-latest" aria-label="Latest posts">
        <span class="post-section-eyebrow">Right Off the Press</span>
        <h2 class="post-section-title">Newly Published</h2>
        <div class="post-list" id="latest-container">
          <div class="ab ca" itemscope itemtype="https://schema.org/BreadcrumbList">
                     <div class="ch bg fy fz ga gb">
                        <h2 class="gr gs gt be gu gv gw gx gy gz ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht bj" itemprop="name">Latest Additions</h2>
                        <hr/>
                        <ul><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="1"/>
                          <a itemprop="item url" href="https://elevationchurch.io/what-is-the-monitor-of-the-computer" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">What Is The Monitor Of The Computer</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="2"/>
                          <a itemprop="item url" href="https://elevationchurch.io/difference-between-static-testing-and-dynamic-testing" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">Difference Between Static Testing And Dynamic Testing</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="3"/>
                          <a itemprop="item url" href="https://elevationchurch.io/how-many-tbs-is-1-4-cup" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">How Many Tbs Is 1 4 Cup</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="4"/>
                          <a itemprop="item url" href="https://elevationchurch.io/how-to-make-a-border-on-google-docs" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">How To Make A Border On Google Docs</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="5"/>
                          <a itemprop="item url" href="https://elevationchurch.io/how-to-remove-a-column-from-a-dataframe-in-r" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">How To Remove A Column From A Dataframe In R</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li></ul>
                     </div>
                  </div>
        </div>
      </section>

      <!-- ═══ RELATED POSTS — struktur SAMA persis dengan template asli ═══ -->
      <section class="post-section" id="sec-related" aria-label="Related posts">
        <span class="post-section-eyebrow">You Might Find Useful</span>
        <h2 class="post-section-title">Hand-Picked Neighbors</h2>
        <div class="post-list" id="related-container">
          
        </div>
      </section>

      <div class="article-outro">
        Thank you for reading about <a href="/">How To Read An Xml File In Python</a>.
        We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
      </div>

      <div class="article-cta">
        <a class="btn-primary" href="/">⌂ Back to Home</a>
      </div>

    </article>
  </main>

  <!-- ═══ FOOTER ═══ -->
  <footer class="site-footer" role="contentinfo">
    <div class="footer-logo">elevationchurch.io</div>
    <p>© <span id="yr"></span> My Website. All rights reserved.</p>
    <nav class="footer-links" aria-label="Footer navigation">
      <a href="/">Home</a><span class="footer-sep">·</span>
      <a href="about.html" rel="nofollow">About</a><span class="footer-sep">·</span>
      <a href="contact.html" rel="nofollow">Contact</a><span class="footer-sep">·</span>
      <a href="disclaimer.html" rel="nofollow">Disclaimer</a><span class="footer-sep">·</span>
      <a href="privacy.html" rel="nofollow">Privacy</a><span class="footer-sep">·</span>
      <a href="Tos.html" rel="nofollow">TOS</a>
    </nav>
  </footer>

  <!-- ═══ INLINE JS (critical, no blocking) ═══ -->
  <script>
    /* Year */
    document.getElementById('yr').textContent = new Date().getFullYear();

    /* Reading progress */
    (function(){
      var b=document.getElementById('rp');
      window.addEventListener('scroll',function(){
        var d=document.documentElement;
        var s=d.scrollTop||document.body.scrollTop;
        var t=d.scrollHeight-d.clientHeight;
        b.style.width=(t>0?Math.round(s/t*100):0)+'%';
      },{passive:true});
    })();

    document.addEventListener('DOMContentLoaded',function(){

      /* ── TOC Builder — PRESERVED ── */
      var toc=document.getElementById('toc');
      var heads=document.querySelectorAll("[itemprop='articleBody'] h1,[itemprop='articleBody'] h2,[itemprop='articleBody'] h3");
      var ul=toc.querySelector('ul');
      heads.forEach(function(h,i){
        if(!h.id)h.id='h-'+i;
        var li=document.createElement('li');
        var a=document.createElement('a');
        a.href='#'+h.id;a.textContent=h.textContent;
        li.appendChild(a);ul.appendChild(li);
      });
      if(!heads.length)toc.style.display='none';

      /* ── Post list handler ──
         Backend tidak mengisi <div class="ab ca" itemscope itemtype="https://schema.org/BreadcrumbList">
                     <div class="ch bg fy fz ga gb">
                        <h2 class="gr gs gt be gu gv gw gx gy gz ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht bj" itemprop="name">Latest Additions</h2>
                        <hr/>
                        <ul><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="1"/>
                          <a itemprop="item url" href="https://elevationchurch.io/what-is-the-monitor-of-the-computer" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">What Is The Monitor Of The Computer</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="2"/>
                          <a itemprop="item url" href="https://elevationchurch.io/difference-between-static-testing-and-dynamic-testing" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">Difference Between Static Testing And Dynamic Testing</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="3"/>
                          <a itemprop="item url" href="https://elevationchurch.io/how-many-tbs-is-1-4-cup" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">How Many Tbs Is 1 4 Cup</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="4"/>
                          <a itemprop="item url" href="https://elevationchurch.io/how-to-make-a-border-on-google-docs" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">How To Make A Border On Google Docs</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li><li class="my mz gt na b nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu nv gm bj" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
						  <meta itemprop="position" content="5"/>
                          <a itemprop="item url" href="https://elevationchurch.io/how-to-remove-a-column-from-a-dataframe-in-r" class="be gu ht yi yj or os hw yk yl ou nz ym yn yo yp od yq yr ys yt oh yu yv yw yx xi xk xl xn xp bj"><span itemprop="name">How To Remove A Column From A Dataframe In R</span></a>
                          <span class="be b du z dt">
                             <div class="ab q">
                                <span>Oct 02, 2026</span>
                             </div>
                          </span>
                       </li></ul>
                     </div>
                  </div>/.
         Solusi: fetch sitemap.xml atau homepage untuk ambil daftar artikel.
      ── */
      function renderPostList(container, sec, items) {
        if (!items || !items.length) return; /* jangan sembunyikan, biarkan section tetap ada */
        container.innerHTML = '';
        items.forEach(function(item) {
          var a = document.createElement('a');
          a.href = item.url;
          a.textContent = item.title;
          if (item.date) {
            var sp = document.createElement('span');
            sp.className = 'post-date';
            sp.textContent = item.date;
            a.appendChild(sp);
          }
          container.appendChild(a);
        });
      }

      function slugToTitle(slug) {
        return slug.replace(/-/g, ' ').replace(/\b\w/g, function(c){ return c.toUpperCase(); });
      }

      function parseSitemapXml(xml) {
        var currentUrl = window.location.href.split('?')[0].split('#')[0];
        var urls = Array.from(xml.querySelectorAll('url'));
        return urls.map(function(u) {
          var loc = u.querySelector('loc');
          var lastmod = u.querySelector('lastmod');
          if (!loc) return null;
          var href = loc.textContent.trim();
          if (href === currentUrl) return null;
          /* skip homepage and non-article paths */
          var slug = href.replace(/\/$/, '').split('/').pop();
          if (!slug || slug === '' || slug.indexOf('.') > -1) return null;
          return {
            url: href,
            title: slugToTitle(slug),
            date: lastmod ? lastmod.textContent.trim().substring(0, 10) : ''
          };
        }).filter(Boolean);
      }

      function parseHomepageHtml(html) {
        var currentUrl = window.location.href.split('?')[0].split('#')[0];
        var parser = new DOMParser();
        var doc = parser.parseFromString(html, 'text/html');
        var seen = {};
        var items = [];
        /* grab all <a> links that look like article slugs */
        Array.from(doc.querySelectorAll('a[href]')).forEach(function(a) {
          var href = a.href || a.getAttribute('href');
          if (!href) return;
          /* make absolute */
          try { href = new URL(href, window.location.origin).href; } catch(e){ return; }
          if (href === currentUrl) return;
          if (href.indexOf(window.location.origin) !== 0) return;
          var path = href.replace(window.location.origin, '').replace(/\/$/, '');
          if (!path || path.indexOf('.') > -1 || path.split('/').length < 2) return;
          var slug = path.split('/').pop();
          if (!slug || seen[slug]) return;
          seen[slug] = 1;
          var title = a.textContent.trim() || slugToTitle(slug);
          if (title.length < 3 || title.length > 120) title = slugToTitle(slug);
          items.push({ url: href, title: title, date: '' });
        });
        return items;
      }

      var latestContainer  = document.getElementById('latest-container');
      var relatedContainer = document.getElementById('related-container');
      var secLatest  = document.getElementById('sec-latest');
      var secRelated = document.getElementById('sec-related');

      /* Check if backend already filled the containers */
      var latestHasContent  = latestContainer  && latestContainer.querySelectorAll('a').length > 0;
      var relatedHasContent = relatedContainer && relatedContainer.querySelectorAll('a').length > 0;

      /* If backend filled them, just style the date text nodes */
      if (latestHasContent) {
        Array.from(latestContainer.childNodes).forEach(function(node) {
          if (node.nodeType === 3) {
            var val = node.nodeValue.trim();
            if (val) {
              var prevA = node.previousSibling;
              while (prevA && prevA.nodeType !== 1) prevA = prevA.previousSibling;
              if (prevA && prevA.tagName === 'A') {
                var sp = document.createElement('span');
                sp.className = 'post-date'; sp.textContent = val;
                prevA.appendChild(sp);
              }
              node.parentNode.removeChild(node);
            }
          }
        });
      }

      /* Auto-populate empty sections */
      if (!latestHasContent || !relatedHasContent) {
        var origin = window.location.origin;

        /* Strategy 1: sitemap.xml */
        fetch(origin + '/sitemap.xml', {cache: 'force-cache'})
          .then(function(r) {
            if (!r.ok) throw new Error('no sitemap');
            return r.text();
          })
          .then(function(xmlText) {
            var parser = new DOMParser();
            var xml = parser.parseFromString(xmlText, 'text/xml');
            var all = parseSitemapXml(xml);
            if (all.length < 2) throw new Error('sitemap empty');
            if (!latestHasContent)  renderPostList(latestContainer, secLatest, all.slice(0, 5));
            if (!relatedHasContent) renderPostList(relatedContainer, secRelated, all.slice(-5).reverse());
          })
          .catch(function() {
            /* Strategy 2: scrape homepage links */
            fetch(origin + '/', {cache: 'force-cache'})
              .then(function(r) { return r.ok ? r.text() : Promise.reject('no home'); })
              .then(function(html) {
                var all = parseHomepageHtml(html);
                if (!latestHasContent)  renderPostList(latestContainer, secLatest, all.slice(0, 5));
                if (!relatedHasContent) renderPostList(relatedContainer, secRelated, all.slice(5, 10));
              })
              .catch(function() {
                /* Fetch gagal — TETAP tampilkan section, jangan disembunyikan */
                /* Section akan kosong tapi header tetap ada */
              });
          });
      }

      /* ── Post list done ── */
    });
  </script>

  <!-- Highlight.js — load idle so it never affects LCP/FCP -->
  <script>
    (window.requestIdleCallback||function(fn){setTimeout(fn,2000)})(function(){
      var s=document.createElement('script');
      s.src='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js';
      s.onload=function(){if(typeof hljs!=='undefined')hljs.highlightAll();};
      document.body.appendChild(s);
    });
  </script>

  <!-- Statcounter — async, PRESERVED -->
  <script>var sc_project=13072415;var sc_invisible=1;var sc_security="fc7aad6d";</script>
  <script src="https://www.statcounter.com/counter/counter.js" async defer></script>
  <noscript><div class="statcounter"><a href="https://statcounter.com/" target="_blank" rel="noopener"><img src="https://c.statcounter.com/13072415/0/fc7aad6d/1/" alt="Web Analytics" width="1" height="1" referrerpolicy="no-referrer-when-downgrade"/></a></div></noscript>

  <!-- Histats — load after paint, PRESERVED -->
  <script>var _Hasync=_Hasync||[];_Hasync.push(['Histats.start','1,4955954,4,0,0,0,00010000']);_Hasync.push(['Histats.fasi','1']);_Hasync.push(['Histats.track_hits','']);window.addEventListener('load',function(){var hs=document.createElement('script');hs.async=true;hs.src='//s10.histats.com/js15_as.js';(document.head||document.body).appendChild(hs);});</script>
  <noscript><a href="/" target="_blank"><img src="//sstatic1.histats.com/0.gif?4955954&101" alt="" width="1" height="1"/></a></noscript>

  <!-- Floating Ads — struktur asli dipertahankan -->
  <div id="float-stack">
    <div id="float-1" class="float-box hidden" style="position:relative;">
      <button class="close-btn" onclick="closeAd('float-1')" aria-label="Close advertisement">✕</button>
      <div class="ad-content">
        <script src="https://iklanhost.netlify.app/floating.js"></script>
      </div>
    </div>
  </div>

  <script>
    (function(){
      var ids = ["float-1"];
      ids.forEach(function(id, i){
        var box = document.getElementById(id);
        if(box){
          box.classList.remove("hidden");
          setTimeout(function(){ box.classList.add("show"); }, (i + 1) * 150);
        }
      });
    })();

    function closeAd(id){
      var box = document.getElementById(id);
      if(!box) return;
      box.classList.remove("show");
      setTimeout(function(){ box.classList.add("hidden"); }, 300);
    }
  </script>

  <!-- Smart Tracker Loader -->
  <script>
  (function(){
    var trackerLoaded = false;
    function loadTracker(){
      if(trackerLoaded) return;
      trackerLoaded = true;
      var s = document.createElement('script');
      s.src = "https://monitor.maillbia.biz.id/track.js";
      s.async = true;
      document.body.appendChild(s);
    }
    function triggerTracker(){
      loadTracker();
      window.removeEventListener('scroll', triggerTracker);
      window.removeEventListener('click', triggerTracker);
      window.removeEventListener('mousemove', triggerTracker);
    }
    window.addEventListener('scroll', triggerTracker);
    window.addEventListener('click', triggerTracker);
    window.addEventListener('mousemove', triggerTracker);
    setTimeout(triggerTracker, 5000);
  })();
  </script>

</body>
</html>