Skip to content

Commit

Permalink
Add CfdiUtils\Cleaner\Cleaner::removeIncompleteSchemaLocations
Browse files Browse the repository at this point in the history
  • Loading branch information
eclipxe13 committed Dec 4, 2018
1 parent 52d99a5 commit 42a030e
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 21 deletions.
4 changes: 3 additions & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
- Remove `trigger_error` on `\CfdiUtils\Elements\Cfdi33\Comprobante::getCfdiRelacionados` when called with arguments.


## Version 2.7.1 2018-12-03
## Version 2.7.1 2018-12-04

- Fix wrong use of `escapeshellcmd` replacing with `escapeshellarg`
- Add argument `-c|--clean` to script `tests/validate.php` to perform clean before validate
Expand All @@ -27,6 +27,8 @@
- Add `Config::getServiceUrl`
- Add `Config::wsdlLocation` property
- Add `--local-wsdl` parameter to `tests/estadosat.php` script
- Add a new step on `CfdiUtils\Cleaner\Cleaner` that removes from `xsi:schemaLocations` the namespaces that are
not followed by a string that ends on `.xsd`


## Version 2.7.0 2018-10-19
Expand Down
5 changes: 5 additions & 0 deletions docs/leer/limpieza-cfdi.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Para evitar estos errores se puede usar el objeto `CfdiUtils\Cleaner\Cleaner`.
Este objeto requiere una cadena de texto con XML válido. Y limpia el XML siguiendo estos pasos:

1. Remueve el nodo `cfdi:Addenda`.
1. Remueve dentro de las locaciones de espacios de nombre `xsi:schemaLocation` los namespaces que no tengan
a continuación una uri que termine en `.xsd`.
1. Remueve todos los nodos que no tengan relación con el SAT (los que no contengan `http://www.sat.gob.mx/`).
1. Remueve todos los pares de espacio de nombre y archivo xsd de los `xsi:schemaLocation` que no tengan relación con el SAT.
1. Remueve todos los espacios de nombres listados que no están en uso.
Expand All @@ -38,3 +40,6 @@ También se puede instanciar un objeto de la clase `CfdiUtils\Cleaner\Cleaner` y
- `load(string $content)`: Carga un contenido XML "sucio"
- `clean()`: Realiza la limpieza
- `retrieveXml()`: Obtiene el contenido XML "limpio"

Si deseas implementar tu propio orden, hacer o agregar nuevos limpiadores puedes extender la clase o sobrescribir
el método `clean` o bien llamar a cada uno de los pasos de limpieza por tu propia cuenta.
49 changes: 43 additions & 6 deletions src/CfdiUtils/Cleaner/Cleaner.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public static function isNameSpaceAllowed(string $namespace): bool
public function clean()
{
$this->removeAddenda();
$this->removeIncompleteSchemaLocations();
$this->removeNonSatNSNodes();
$this->removeNonSatNSschemaLocations();
$this->removeUnusedNamespaces();
Expand Down Expand Up @@ -157,6 +158,37 @@ public function removeAddenda()
}
}

/**
* Procedure to drop schemaLocations where second part does not ends with '.xsd'
*
* @return void
*/
public function removeIncompleteSchemaLocations()
{
$schemaLocations = $this->obtainXsiSchemaLocations();
for ($s = 0; $s < $schemaLocations->length; $s++) {
$element = $schemaLocations->item($s);
if (null !== $element) {
$element->nodeValue = $this->removeIncompleteSchemaLocation($element->nodeValue);
}
}
}

public function removeIncompleteSchemaLocation(string $source): string
{
$components = array_values(array_filter(array_map('trim', explode(' ', $source))));
$length = count($components);
for ($c = 0; $c < $length; $c = $c + 1) {
$xsd = $components[$c + 1] ?? '';
if ((0 === strcasecmp('.xsd', substr($xsd, -4, 4)))) {
$c = $c + 1;
continue;
}
$components[$c] = '';
}
return strval(implode(' ', array_filter($components)));
}

/**
* Procedure to drop schemaLocations that are not allowed
* If the schemaLocation is empty then remove the attribute
Expand All @@ -165,12 +197,7 @@ public function removeAddenda()
*/
public function removeNonSatNSschemaLocations()
{
// Do not assume that prefix for http://www.w3.org/2001/XMLSchema-instance is "xsi"
$xsi = $this->dom()->lookupPrefix('http://www.w3.org/2001/XMLSchema-instance');
if (! $xsi) {
return;
}
$schemaLocations = $this->xpathQuery("//@$xsi:schemaLocation");
$schemaLocations = $this->obtainXsiSchemaLocations();
for ($s = 0; $s < $schemaLocations->length; $s++) {
$element = $schemaLocations->item($s);
if (null !== $element) {
Expand Down Expand Up @@ -265,6 +292,16 @@ public function removeUnusedNamespaces()
}
}

private function obtainXsiSchemaLocations(): DOMNodeList
{
// Do not assume that prefix for http://www.w3.org/2001/XMLSchema-instance is "xsi"
$xsi = $this->dom()->lookupPrefix('http://www.w3.org/2001/XMLSchema-instance');
if (! $xsi) {
return new DOMNodeList();
}
return $this->xpathQuery("//@$xsi:schemaLocation");
}

/**
* Helper function to perform a XPath query using an element (or root element)
* @param string $query
Expand Down
33 changes: 25 additions & 8 deletions tests/CfdiUtilsTests/Cleaner/CleanerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ public function testCleanOnDetail()
{
$basefile = $this->utilAsset('cleaner/v32-dirty.xml');
$step1 = $this->utilAsset('cleaner/v32-no-addenda.xml');
$step2 = $this->utilAsset('cleaner/v32-no-nonsat-nodes.xml');
$step3 = $this->utilAsset('cleaner/v32-no-nonsat-schemalocations.xml');
$step4 = $this->utilAsset('cleaner/v32-no-nonsat-xmlns.xml');
foreach ([$basefile, $step1, $step2, $step3, $step4] as $filename) {
$step2 = $this->utilAsset('cleaner/v32-no-incomplete-schemalocations.xml');
$step3 = $this->utilAsset('cleaner/v32-no-nonsat-nodes.xml');
$step4 = $this->utilAsset('cleaner/v32-no-nonsat-schemalocations.xml');
$step5 = $this->utilAsset('cleaner/v32-no-nonsat-xmlns.xml');
foreach ([$basefile, $step1, $step3, $step2, $step4, $step5] as $filename) {
$this->assertFileExists($basefile, "The file $filename for testing does not exists");
}
$cleaner = new Cleaner(file_get_contents($basefile));
Expand All @@ -88,29 +89,36 @@ public function testCleanOnDetail()
'Compare that addenda was removed'
);

$cleaner->removeNonSatNSNodes();
$cleaner->removeIncompleteSchemaLocations();
$this->assertXmlStringEqualsXmlFile(
$step2,
$cleaner->retrieveXml(),
'Compare that incomplete schemaLocations were removed'
);

$cleaner->removeNonSatNSNodes();
$this->assertXmlStringEqualsXmlFile(
$step3,
$cleaner->retrieveXml(),
'Compare that non SAT nodes were removed'
);

$cleaner->removeNonSatNSschemaLocations();
$this->assertXmlStringEqualsXmlFile(
$step3,
$step4,
$cleaner->retrieveXml(),
'Compare that non SAT schemaLocations were removed'
);

$cleaner->removeUnusedNamespaces();
$this->assertXmlStringEqualsXmlFile(
$step4,
$step5,
$cleaner->retrieveXml(),
'Compare that xmlns definitions were removed'
);

$this->assertXmlStringEqualsXmlFile(
$step4,
$step5,
Cleaner::staticClean(file_get_contents($basefile)),
'Check static method for cleaning is giving the same results as detailed execution'
);
Expand Down Expand Up @@ -161,4 +169,13 @@ public function testRemoveNonSatNSschemaLocationsRemoveEmptySchemaLocation()
$cleaner->removeNonSatNSschemaLocations();
$this->assertXmlStringEqualsXmlString($xmlExpectedContent, $cleaner->retrieveXml());
}

public function testRemoveIncompleteSchemaLocation()
{
// source include spaces to ensure that is working properly
$source = ' bleh foo foo.xsd bar baz zoo zoo.xsd baa xee xee.xsd bah ';
$expected = 'foo foo.xsd zoo zoo.xsd xee xee.xsd';
$cleaner = new Cleaner('');
$this->assertSame($expected, $cleaner->removeIncompleteSchemaLocation($source));
}
}
2 changes: 1 addition & 1 deletion tests/assets/cleaner/v32-dirty.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:add="http://example.org/add" xmlns:xyz="http://example.org/xyz"
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd http://example.org/add http://example.org/xsd/add.xsd http://example.org/xyz http://example.org/xsd/xyz.xsd"
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd http://example.org/add http://example.org/xsd/add.xsd http://www.sat.gob.mx/orphan1 http://www.sat.gob.mx/orphan2 http://example.org/xyz http://example.org/xsd/xyz.xsd http://www.sat.gob.mx/orphan3"
version="3.2">
<cfdi:Addenda>
<ext:ElementosExtra xmlns:ext="http://example.com/xsd/ext">
Expand Down
2 changes: 1 addition & 1 deletion tests/assets/cleaner/v32-no-addenda.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:add="http://example.org/add" xmlns:xyz="http://example.org/xyz"
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd http://example.org/add http://example.org/xsd/add.xsd http://example.org/xyz http://example.org/xsd/xyz.xsd"
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd http://example.org/add http://example.org/xsd/add.xsd http://www.sat.gob.mx/orphan1 http://www.sat.gob.mx/orphan2 http://example.org/xyz http://example.org/xsd/xyz.xsd http://www.sat.gob.mx/orphan3"
version="3.2">

<cfdi:Complemento>
Expand Down
11 changes: 11 additions & 0 deletions tests/assets/cleaner/v32-no-incomplete-schemalocations.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:add="http://example.org/add" xmlns:xyz="http://example.org/xyz"
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd http://example.org/add http://example.org/xsd/add.xsd http://example.org/xyz http://example.org/xsd/xyz.xsd"
version="3.2">

<cfdi:Complemento>
<tfd:TimbreFiscalDigital xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigital.xsd" version="1.0"/>
<add:point x="1" y="2" add:removed="Check if this attributte is removed"/>
</cfdi:Complemento>
</cfdi:Comprobante>
4 changes: 2 additions & 2 deletions tests/assets/cleaner/v32-no-nonsat-nodes.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:add="http://example.org/add" xmlns:xyz="http://example.org/xyz"
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd http://example.org/add http://example.org/xsd/add.xsd http://example.org/xyz http://example.org/xsd/xyz.xsd"
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd http://example.org/add http://example.org/xsd/add.xsd http://example.org/xyz http://example.org/xsd/xyz.xsd"
version="3.2">

<cfdi:Complemento>
<tfd:TimbreFiscalDigital xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigital.xsd" version="1.0"/>

</cfdi:Complemento>
</cfdi:Comprobante>
2 changes: 1 addition & 1 deletion tests/assets/cleaner/v32-no-nonsat-schemalocations.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

<cfdi:Complemento>
<tfd:TimbreFiscalDigital xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigital.xsd" version="1.0"/>

</cfdi:Complemento>
</cfdi:Comprobante>
2 changes: 1 addition & 1 deletion tests/assets/cleaner/v32-no-nonsat-xmlns.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@

<cfdi:Complemento>
<tfd:TimbreFiscalDigital xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigital.xsd" version="1.0"/>

</cfdi:Complemento>
</cfdi:Comprobante>

0 comments on commit 42a030e

Please sign in to comment.