Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/eclipxe13/CfdiUtils/llms.txt

Use this file to discover all available pages before exploring further.

In practice, CFDI files received from third parties are often technically valid under SAT rules but contain XML errors that break strict parsing or validation. This happens because the SAT (or a PAC acting on the SAT’s behalf) signs the CFDI and then allows additional content — such as cfdi:Addenda data — to be appended after signing. That post-signing content is outside the cadena de origen and does not invalidate the digital seal, but it frequently introduces XML issues that cause downstream processing failures. The CfdiUtils\Cleaner\Cleaner class repairs these common problems before you pass the XML to the Cfdi constructor or a validator.

What the Cleaner Does

Calling clean() on a loaded Cleaner object applies the following operations in order:
  1. Fix incorrect xmlns:schemaLocation — Some SAT-issued CFDI documents incorrectly use xmlns:schemaLocation instead of xsi:schemaLocation. This is corrected as a string operation before the XML is parsed.
  2. Remove bare CFDI 3 namespace declaration — If the document declares xmlns="http://www.sat.gob.mx/cfd/3" (no prefix) alongside the correct prefixed declaration xmlns:cfdi="http://www.sat.gob.mx/cfd/3", the bare declaration is removed.
  3. Remove cfdi:Addenda — The entire cfdi:Comprobante/cfdi:Addenda node is removed. Its content is outside the cadena de origen and is a common source of invalid XML.
  4. Remove incomplete schemaLocation entries — Pairs in xsi:schemaLocation where the second URI does not end in .xsd are removed.
  5. Remove non-SAT namespace nodes — All XML elements whose namespace does not start with http://www.sat.gob.mx/ or http://www.w3.org/ are removed.
  6. Remove non-SAT schemaLocation pairs — Namespace/XSD pairs in xsi:schemaLocation that reference non-SAT namespaces are removed.
  7. Remove unused namespace declarations — Any xmlns:* declarations that are no longer referenced after the previous steps are stripped.
  8. Collapse multiple cfdi:Complemento nodes — The Anexo 20 specification allows only one cfdi:Complemento, but the XSD permits many. Multiple occurrences are merged into a single node, preserving child order so the cadena de origen remains identical.
  9. Fix known SAT XSD URLs — Known incorrect or outdated XSD location URLs for CFDI and Timbre Fiscal Digital are corrected.
The cleaner modifies the XML document. Always work on a copy if you need to preserve the original bytes. Cleaning is a lossy operation — cfdi:Addenda content is permanently removed.

Basic Usage

Static one-liner

The fastest way to clean a CFDI string is the static helper Cleaner::staticClean(). It creates a Cleaner internally, calls clean(), and returns the cleaned XML string.
<?php
$possibleDirty = file_get_contents('/cfdi/recibidos/FEI-456823.xml');

$cleanContent = \CfdiUtils\Cleaner\Cleaner::staticClean($possibleDirty);

// Now safe to parse
$cfdi = \CfdiUtils\Cfdi::newFromString($cleanContent);

Object-oriented usage

Create a Cleaner instance, then call clean() followed by retrieveXml():
<?php
$content = file_get_contents('/cfdi/recibidos/FEI-456823.xml');

$cleaner = new \CfdiUtils\Cleaner\Cleaner($content);
$cleaner->clean();
$cleanContent = $cleaner->retrieveXml();

$cfdi = \CfdiUtils\Cfdi::newFromString($cleanContent);
retrieveXml() returns the cleaned XML as a string. If you need the DOM object, use retrieveDocument() instead, which returns a clone of the internal DOMDocument.

Individual Cleaning Operations

If you want finer control — for example, to skip certain steps or run them in a different order — you can call each operation individually on a loaded Cleaner instance:
MethodWhat it does
removeAddenda()Removes the cfdi:Comprobante/cfdi:Addenda node
removeIncompleteSchemaLocations()Drops xsi:schemaLocation pairs where the XSD URI does not end in .xsd
removeNonSatNSNodes()Removes all elements whose namespace is not SAT-owned
removeNonSatNSschemaLocations()Removes non-SAT pairs from all xsi:schemaLocation attributes
removeUnusedNamespaces()Removes xmlns:* declarations that are no longer in use
collapseComprobanteComplemento()Merges multiple cfdi:Complemento elements into one
fixKnownSchemaLocationsXsdUrls()Corrects known incorrect SAT XSD URLs

Skipping the Pre-load Cleaning Steps

The first two operations (fixing xmlns:schemaLocation and removing the bare CFDI 3 namespace) are applied as string transformations before the XML is parsed. They are handled by an injected BeforeLoadCleanerInterface implementation. To skip them, pass a null-object implementation to the constructor:
<?php
$content = '... el xml del cfdi ...';

// A null implementation of BeforeLoadCleanerInterface — does nothing
$nullBeforeLoadCleaner = new class () implements \CfdiUtils\Cleaner\BeforeLoad\BeforeLoadCleanerInterface {
    public function clean(string $content): string
    {
        return $content;
    }
};

$cleaner = new \CfdiUtils\Cleaner\Cleaner($content, $nullBeforeLoadCleaner);
$cleaner->clean();
$cleanContent = $cleaner->retrieveXml();

Version Support

The Cleaner only processes CFDI versions 3.2, 3.3, and 4.0. You can check whether a given version string is supported with the static helper:
<?php
\CfdiUtils\Cleaner\Cleaner::isVersionAllowed('4.0');  // true
\CfdiUtils\Cleaner\Cleaner::isVersionAllowed('2.0');  // false

Namespace Allowlist

The cleaner keeps namespaces that belong to the SAT or to W3C standards. You can check whether any namespace URI would be preserved with:
<?php
\CfdiUtils\Cleaner\Cleaner::isNameSpaceAllowed('http://www.sat.gob.mx/cfd/4');  // true
\CfdiUtils\Cleaner\Cleaner::isNameSpaceAllowed('http://www.w3.org/2001/XMLSchema-instance');  // true
\CfdiUtils\Cleaner\Cleaner::isNameSpaceAllowed('http://www.example.com/addenda');  // false

When to Use

1

Receiving CFDI from third parties

Always clean CFDI files received from clients, suppliers, or data feeds before parsing or validating them. Post-signing additions are common and frequently contain XML errors.
2

Before validation

Run the cleaner before feeding the XML into the CfdiUtils validators. Validation errors caused by extraneous namespaces or a malformed Addenda can mask genuine compliance issues.
3

Before long-term storage

Stripping non-SAT nodes and fixing schema locations produces a canonical, minimal XML that is smaller and less prone to future compatibility problems.

Build docs developers (and LLMs) love