XML

How to store and query XML documents in PostgreSQL using the XML data type: XMLPARSE, the xpath() function, extracting fields, filtering rows, and creating indexes on XML data.

5 min read · Last updated: March 2026 · Back to overview

Quick Answer

The PostgreSQL XML data type stores well-formed XML documents or content fragments with built-in validation. Use XMLPARSE() to insert XML data and xpath() to extract values using XPath expressions.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

Introduction to the PostgreSQL XML data type

The XML data type stores well-formed XML documents directly in the database. PostgreSQL validates XML on insert and provides built-in functions for parsing and querying with XPath.

Declare an XML column with:

column_name XML

Benefits include type safety (PostgreSQL rejects malformed XML) and built-in XPath support via the xpath() function.

Creating a table and inserting XML data

CREATE TABLE person (
  id   INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  info XML
);

-- Insert a full XML document using XMLPARSE
INSERT INTO person (info) VALUES (
  XMLPARSE(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?>
  <person>
    <name>John Doe</name>
    <age>35</age>
    <city>San Francisco</city>
  </person>')
);

INSERT INTO person (info) VALUES
  (XMLPARSE(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?><person><name>Jane Doe</name><age>30</age><city>San Francisco</city></person>')),
  (XMLPARSE(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?><person><name>John Smith</name><age>40</age><city>New York</city></person>')),
  (XMLPARSE(DOCUMENT '<?xml version="1.0" encoding="UTF-8"?><person><name>Alice Johnson</name><age>30</age><city>Los Angeles</city></person>'));

Querying XML with xpath()

-- Extract names as an array of XML values
SELECT xpath('/person/name/text()', info) AS name
FROM person;
-- {"John Doe"}, {"Jane Doe"}, {"John Smith"}, {"Alice Johnson"}

-- Extract the first element as text
SELECT (xpath('/person/name/text()', info))[1]::text AS name
FROM person;
-- John Doe / Jane Doe / John Smith / Alice Johnson

-- Extract age as an integer (XML -> text -> integer, no direct cast)
SELECT (xpath('/person/age/text()', info))[1]::text::integer AS age
FROM person;

Extracting multiple fields at once

SELECT
  (xpath('/person/name/text()', info))[1]::text AS name,
  (xpath('/person/age/text()',  info))[1]::text::integer AS age,
  (xpath('/person/city/text()', info))[1]::text AS city
FROM person;

-- Output:
-- name          | age |     city
-- --------------+-----+---------------
-- John Doe      |  35 | San Francisco
-- Jane Doe      |  30 | San Francisco
-- John Smith    |  40 | New York
-- Alice Johnson |  30 | Los Angeles

Filtering rows by XML content

SELECT * FROM person
WHERE (xpath('/person/name/text()', info))[1]::text = 'Jane Doe';

Creating an index on XML data

XPath queries on large tables are slow without an index. Create an expression index:

CREATE INDEX person_name
ON person USING BTREE (cast(xpath('/person/name', info) AS text[]));

-- Query using the same expression to trigger the index
EXPLAIN ANALYZE
SELECT * FROM person
WHERE cast(xpath('/person/name', info) AS text[]) = '{<name>Jane Doe</name>}';

Production tips

  • For new designs, prefer JSONB over XML — it has richer operator support, better indexing, and is more commonly used in modern applications.
  • Use the XML type when integrating with systems that produce or require XML (legacy enterprise APIs, SOAP services, XSLT pipelines).
  • Always cast extracted XML values to text before casting to another type — PostgreSQL does not support direct casting from XML to integer or date.
  • Create expression indexes on frequently queried XPath expressions to avoid full table scans.

Reference: PostgreSQL documentation — XML type.

Continue in PostgreSQL Data Types: BYTEA.

Related in this section: Boolean · CHAR, VARCHAR, and TEXT · NUMERIC

Frequently Asked Questions

What is the PostgreSQL XML data type?

The XML data type stores XML documents or XML content fragments. PostgreSQL validates that inserted data is well-formed XML. It provides built-in functions for querying (xpath()), generating (xmlelement(), xmlforest()), and transforming XML data. The type is useful for integrating with systems that produce or consume XML, such as legacy enterprise APIs.

How do you insert XML data into PostgreSQL?

Use XMLPARSE() to convert a text string into an XML value: INSERT INTO person (info) VALUES (XMLPARSE(DOCUMENT '<?xml version="1.0"?><person><name>John</name></person>')); Use DOCUMENT when the input is a full XML document (with declaration and root element). Use CONTENT when the input is a fragment.

How do you query values from XML data in PostgreSQL?

Use the xpath() function with an XPath expression: SELECT xpath('/person/name/text()', info) FROM person; This returns an array of XML values. To get the first element as text, use: (xpath('/person/name/text()', info))[1]::text — cast to text is required because you cannot cast XML directly to most other types.

How do you filter rows by an XML field value?

Use xpath() in the WHERE clause: SELECT * FROM person WHERE (xpath('/person/name/text()', info))[1]::text = 'Jane Doe'; For better performance on large tables, create an expression index on the extracted value.

How do you index XML data in PostgreSQL?

Create a B-tree expression index on the extracted value: CREATE INDEX person_name ON person USING BTREE (cast(xpath('/person/name', info) AS text[])); Then query using the same expression in WHERE: WHERE cast(xpath('/person/name', info) AS text[]) = '{"<name>Jane Doe</name>"}'; PostgreSQL will use the index instead of scanning all rows.