1

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?

Salim Djerbouh
  • 10,719
  • 6
  • 29
  • 61
Sarah
  • 292
  • 1
  • 10

2 Answers2

2

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.

ThW
  • 19,120
  • 3
  • 22
  • 44
  • I couldn't find better! Thank you very much for your interest. I've wasted days with SimpleXML with no great success. Thanks again. You are magnificent! – Sarah Dec 14 '22 at 17:29
0

First, your desired xml (as well as the one in the question you link to) is not well formed for several reasons.

Second, even after that's fixed (see below), it's not clear to me why you're going about it the way you do.

How about this way:

$string = '<?xml version="1.0" encoding="UTF-8"?>
<root>
   <p:FatturaElettronica xmlns:p="http://microsoft.com/wsdl/types/" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 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>
</root>';                                                                       
$xml = simplexml_load_string($string);

echo $xml->asXML() ."\r\n";

That should echo your well-formed xml.

Jack Fleeting
  • 24,385
  • 6
  • 23
  • 45
  • I need to create it using simplexml methods, like addChild and so on. Can you show me a complete answer with these methods please? – Sarah Dec 13 '22 at 22:29
  • @Sarah I'm sorry, but I'm afraid not. Doing something in 20 steps (and error prone, as you have experienced) when you can do it in one step just seems too much work. I didn't realize you are required to do it the long way. I'm going to leave the answer in place in case some future reader can use it. – Jack Fleeting Dec 13 '22 at 22:53