Search code examples
phpxmlsimplexml

SimpleXML root node prefix php with default namespace declaration


I'm creating an xml file with PHP. The file I need to create is this one I show you:

<p:FatturaElettronica versione="FPA12" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" versione="FPA12" >
 <FatturaElettronicaHeader>
  <DatiTrasmissione>
   <IdTrasmittente>
    <IdPaese>IT</IdPaese>
    <IdCodice>01234567890</IdCodice>
   </IdTrasmittente>
   <ProgressivoInvio>00001</ProgressivoInvio>
   <FormatoTrasmissione>FPA12</FormatoTrasmissione>
   <CodiceDestinatario>AAAAAA</CodiceDestinatario>
  </DatiTrasmissione>
  </FatturaElettronicaHeader>
<p:FatturaElettronica>

This is my code:

$xml = new SimpleXMLElement('<p:FatturazioneElettronica xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:p="http://microsoft.com/wsdl/types/" />');
$xml->addAttribute("versione","FPA12");
$xml->addAttribute("xmlns:xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
$FatturaElettronicaHeader = $xml->addChild('FatturaElettronicaHeader');
$DatiTrasmissione=$FatturaElettronicaHeader->addChild('DatiTrasmissione');
$IdTrasmittente=$DatiTrasmissione->addChild('IdTrasmittente');
$IdTrasmittente->addChild('IdPaese', 'IT');
$IdTrasmittente->addChild('IdCodice','01234567890');

$ProgressivoInvio=$DatiTrasmissione->addChild('ProgressivoInvio', '00001');
$FormatoTrasmissione=$DatiTrasmissione->addChild('DatiTrasmissione', 'FPA12');
$CodiceDestinatario=$DatiTrasmissione->addChild('CodiceDestinatario', 'AAAAAA');

Because in my created file I initially had the prefix p: in each tag, as shown below

<p:FatturazioneElettronica xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" versione="FPA12">
 <p:FatturaElettronicaHeader>
   <p:DatiTrasmissione>
    <p:IdTrasmittente>
     <p:IdPaese>IT</p:IdPaese>
     <p:IdCodice>01234567890</p:IdCodice>
    </p:IdTrasmittente>
    <p:ProgressivoInvio>00001</p:ProgressivoInvio>
   <p:DatiTrasmissione>FPA12</p:DatiTrasmissione>
   <p:CodiceDestinatario>AAAAAA</p:CodiceDestinatario>
 </p:DatiTrasmissione>

while this prefix p: must be only in the root node (p:FatturaElettronica) I added xmlns="http://dummy.com"

<p:FatturazioneElettronica xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" versione="FPA12" xmlns="http://dummy.com">

and

$fatturaelettronicaheader = $xml->addChild('FatturaElettronicaHeader', '', 'http://dummy.com');

as it was suggested in this question

Only this 'http://dummy.com' is not present in the original xml file.

How can I solve this problem or possibly eliminate it before actually generating the file?


Solution

  • SimpleXML abstracts nodes and has some automatic logic for namespaces. That works fine for basic/simple XML structures.

    For more complex XML structures you want to be explicit - so use DOM. It has specific methods for different node types with and without namespaces.

    // define a list with the used namespaces
    $namespaces = [
      'xmlns' => 'http://www.w3.org/2000/xmlns/',
      'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
      'signature' => 'http://www.w3.org/2000/09/xmldsig#',
      'wsdl-types' => 'http://microsoft.com/wsdl/types/'
    ];
    
    $document = new DOMDocument('1.0', 'UTF-8');
    // create and append an element with a namespace
    // this will add the namespace definition for the prefix "p" also
    $document->appendChild(
        $root = $document->createElementNS($namespaces['wsdl-types'], 'p:FatturazioneElettronica')
    );
    // set an attribute without a namespace
    $root->setAttribute('versione', 'FPA12');
    // add namespace definitions using the reserved "xmlns" namespace
    $root->setAttributeNS($namespaces['xmlns'], 'xmlns:xsi', $namespaces['xsi']);
    $root->setAttributeNS($namespaces['xmlns'], 'xmlns:ds', $namespaces['signature']);
    
    // create and append the an element - keep in variable for manipulation
    // the element does not have a namespace
    $root->appendChild(
        $header = $document->createElement('FatturaElettronicaHeader')    
    );
    $header->appendChild(
        $dati = $document->createElement('DatiTrasmissione')
    );
    
    $dati->appendChild(
        $id = $document->createElement('IdTrasmittente')
    );
    
    // create and append element, set text content using a chained call 
    $id
        ->appendChild($document->createElement('IdPaese'))
        ->textContent = 'IT';
    $id
        ->appendChild($document->createElement('IdCodice'))
        ->textContent = '01234567890';
      
    $dati
        ->appendChild($document->createElement('ProgressivoInvio'))
        ->textContent = '00001';
    $dati
        ->appendChild($document->createElement('FormatoTrasmissione'))
        ->textContent = 'FPA12';
    $dati
        ->appendChild($document->createElement('CodiceDestinatario'))
        ->textContent = 'AAAAAA';
    
    $document->formatOutput = TRUE;
    echo $document->saveXML();
    

    Output:

    <?xml version="1.0" encoding="UTF-8"?>
    <p:FatturazioneElettronica xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" versione="FPA12">
      <FatturaElettronicaHeader>
        <DatiTrasmissione>
          <IdTrasmittente>
            <IdPaese>IT</IdPaese>
            <IdCodice>01234567890</IdCodice>
          </IdTrasmittente>
          <ProgressivoInvio>00001</ProgressivoInvio>
          <FormatoTrasmissione>FPA12</FormatoTrasmissione>
          <CodiceDestinatario>AAAAAA</CodiceDestinatario>
        </DatiTrasmissione>
      </FatturaElettronicaHeader>
    </p:FatturazioneElettronica>
    

    Be aware that in your XML p:FatturazioneElettronica has a namespace. It resolves to {http://microsoft.com/wsdl/types/}FatturazioneElettronica. However I don't think that FatturazioneElettronica is a valid element in the WSDL types namespace.

    FatturaElettronicaHeader (and the descandant nodes) do not have a namespace.