how can i generate this XML format with this element - php

This is what the output should be:
<invoice:company this="1">
<invoice:transport from="7777777777" to="77777777777">
<invoice:via via="7777777777" id="1"/>
</invoice:transport>
</invoice:company>
But I am getting this:
<company this="1">
<transport from="7777777777" to="77777777777">
<via via="7777777777" id="1"/>
</transport>
</company>
I am using this as XML generator:
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><invoice>
</invoice>');
//child of invoice
$company= $xml->addChild('company');
//child of company
$transport = $processing->addChild('transport');
$transport->addAttribute('to','77777777777');
$transport->addAttribute('from','77777777777');
//child of transport
$via = $transport->addChild('via');
$via->addAttribute('id','1');
$via->addAttribute('via','77777777777');
$xml->saveXML();
$xml->asXML("company_001.xml");'
Why is ":" on the element tag? how can I do that? I need to have that too.

As mentioned in the comment, invoice: is the namespace of the elements in the document.
When creating an XML document with a namespace, you need to declare it. In the code below, in this I've done it in the initial document loaded into SimpleXMLElement. I don't know the correct definition of this namespace - so I've used "http://some.url" throughout (and all references need to be changed). If you don't define this namespace, SimpleXML will add it's own definition the first time you use it.
When adding the elements in, you can define which namespace they get added to, the third parameter of addChild is the namespace.
So...
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?>
<invoice xmlns:invoice="http://some.url">
</invoice>');
//child of invoice
$processing= $xml->addChild('company', "", "http://some.url");
//child of company
$transport = $processing->addChild('transport', "", "http://some.url");
$transport->addAttribute('to','77777777777');
$transport->addAttribute('from','77777777777');
//child of transport
$via = $transport->addChild('via', "", "http://some.url");
$via->addAttribute('id','1');
$via->addAttribute('via','77777777777');
echo $xml->asXML();
Produces (I've formated the output to help)...
<?xml version="1.0" encoding="utf-8"?>
<invoice xmlns:invoice="http://some.url">
<invoice:company>
<invoice:transport to="77777777777" from="77777777777">
<invoice:via id="1" via="77777777777" />
</invoice:transport>
</invoice:company>
</invoice>
As I'm not sure if this is the entire document your creating, there may need to be minor changes, but hope this helps.

Related

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?
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.
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.

Add xml-stylesheet tag simpleXML php

Hy guys this is my simple code:
$xml = new SimpleXMLElement('<p:FatturazioneElettronica xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dummy.com"/>');
$xml->addAttribute("versione","FPR12");
$FatturaElettronicaHeader = $xml->addChild('FatturaElettronicaHeader',null,'http://dummy.com');
the xml results is:
<p:FatturazioneElettronica xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dummy.com" versione="FPR12">
<FatturaElettronicaHeader>
<DatiTrasmissione>
....
How can add at the top of my xml "xml-stylesheet"?
<?xml-stylesheet type="text/xsl" href="fatturapa_v1.2.xsl" ?>
SimpleXML isn't very good at doing anything other than simple things (think that's were the name is very apt). The only way I can think of doing it is to use DOMDocument, which provides a richer API and you should be able to do it as follows...
$xmlD = new DOMDocument( "1.0", "ISO-8859-15" );
$xmlD->appendChild($xmlD->createProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="fatturapa_v1.2.xsl"'));
$xmlD->appendChild($xmlD->importNode(dom_import_simplexml($xml)));
echo $xmlD->saveXML();
This creates a new DOMDocument instance and then adds a few things. First it uses createProcessingInstruction() to add the processing instruction for the style sheet. Then it imports the existing contents of your SimpleXML document (in $xml) and appends this to the end. The echo should give you a document something like...
<?xml version="1.0" encoding="ISO-8859-15"?>
<?xml-stylesheet type="text/xsl" href="fatturapa_v1.2.xsl"?>
<p:FatturazioneElettronica xmlns:p="http://microsoft.com/wsdl/types/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://dummy.com" versione="FPR12"/>

PHP SimpleXMLElement addAttribute namespaces syntax

I'm working with SimpleXMLElement for the first time and need to generate a line in my XML as follows:
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
I haven't used addAttribute with namespaces before and can't get the correct syntax working here - I've started with this:
$node = new SimpleXMLElement('< Product ></Product >');
$node->addAttribute("xmlns:", "xsd:", 'http://www.w3.org/2001/XMLSchema-instance');
but can't work out how to correct this for the appropriate syntax to generate the desired output?
solution 1: add a prefix to the prefix
<?php
$node = new SimpleXMLElement('<Product/>');
$node->addAttribute("xmlns:xmlns:xsi", 'http://www.w3.org/2001/XMLSchema-instance');
$node->addAttribute("xmlns:xmlns:xsd", 'http://www.w3.org/2001/XMLSchema');
echo $node->asXML();
output:
<?xml version="1.0"?>
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
note: this is a workaround and actually doesn't set the namespace for the attribute, but just quite enough if you are going to echo / save to file the result
solution 2: put namespace directly in the SimpleXMLElement constructor
<?php
$node = new SimpleXMLElement('<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>');
echo $node->asXML();
output is the same as in solution 1
solution 3 (adds additional attribute)
<?php
$node = new SimpleXMLElement('<Product/>');
$node->addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance", "xmlns");
$node->addAttribute("xmlns:xsd", 'http://www.w3.org/2001/XMLSchema', "xmlns");
echo $node->asXML();
output adds additional xmlns:xmlns="xmlns"
<?xml version="1.0"?>
<Product xmlns:xmlns="xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>

php SimpleXML get full namespace attributes [duplicate]

I'd like to get the content of the attribute xsi:schemaLocation. It's works perfectly with getElementsByTagName in php (and foreach after) but it's ugly, right ?
How to get the same content with a simple Xpath query ?
Here a short example of the xml content :
<?xml version="1.0" encoding="utf-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0" creator="blabla" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd" xmlns="http://www.topografix.com/GPX/1/0">
...
</gpx>
Thanks!
Typically you need to register the namespaces you want to use with the XPath library first. Then you can query the attribute by including namespace prefix along with the name.
So let's assume you're using DOMXPath, you might register the following namespaces:
$xpath = new DOMXPath($doc);
$xpath->registerNamespace("xsi","http://www.w3.org/2001/XMLSchema-instance");
$xpath->registerNamespace("gpx", "http://www.topografix.com/GPX/1/0");
And then you can query the schemaLocation attribute with something like this:
$xpath->query("/gpx:gpx/#xsi:schemaLocation",$doc);
Using the SimpleXMLElement class you can easily get the attribute xsi:schemaLocation's value:
<?php
$xml = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0" creator="blabla" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd" xmlns="http://www.topografix.com/GPX/1/0">
</gpx>
XML;
$sxe = new SimpleXMLElement($xml);
$schemaLocation = $sxe->attributes('xsi', true)->schemaLocation;
echo (string) $schemaLocation;

Making the nodes to ignore namespaces (prefixes) after changing XML structure. PHP DOMDocument

Original XML (myfile.xml)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blabla
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:blabla="http://www.w3.org/2000/blabla"
xmlns="http://www.w3.org/2000/blabla"
version="1.0">
<title>Hello there</title>
<metadata>
<rdf:RDF>
<cc:whtaat />
</rdf:RDF>
</metadata>
<sometag>
<anothertag id="anothertag1111">
<andanother id="yep" />
</anothertag >
</sometag>
</blabla>
The aim is adding a child straight under the document root node and "pushing" the "original" children under the new child:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blabla
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:blabla="http://www.w3.org/2000/blabla"
xmlns="http://www.w3.org/2000/blabla"
version="1.0">
<magic>
<title>Hello there</title>
<metadata>
<rdf:RDF>
<cc:whtaat />
</rdf:RDF>
</metadata>
<sometag>
<anothertag id="anothertag1111">
<andanother id="yep" />
</anothertag >
</sometag>
</magic>
</blabla>
This php script does that
<?php
header("Content-type: text/xml");
// Create dom document
$doc = new DOMDocument();
$doc->load("myfile.xml");
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
// Get first child (blabla)
$blablaNode = $doc->firstChild;
// Crete magic element to hold all children in blabla
$magicElement = $doc->createElement('magic');
while($blablaNode->hasChildNodes()) {
// Remove child from blablaNode and append it into magicElement
$magicElement->appendChild($blablaNode->removeChild($blablaNode->firstChild));
}
// Append magicElement to blablaNode
$magicElement = $blablaNode->appendChild($magicElement);
echo $doc->saveXML();
?>
however the output is
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blabla xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:blabla="http://www.w3.org/2000/blabla"
xmlns="http://www.w3.org/2000/blabla" version="1.0">
<magic>
<blabla:title xmlns:default="http://www.w3.org/2000/blabla">Hello there</blabla:title>
<blabla:metadata xmlns:default="http://www.w3.org/2000/blabla" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#">
<rdf:RDF>
<cc:whtaat/>
</rdf:RDF>
</blabla:metadata>
<blabla:sometag xmlns:default="http://www.w3.org/2000/blabla">
<blabla:anothertag id="anothertag1111">
<blabla:andanother id="yep"/>
</blabla:anothertag>
</blabla:sometag>
</magic>
</blabla>
So every node (that is in the "default" namespace) has "blaba" prefix attached to it
<blabla:title />
How to avoid that?
When inspecting the ongoings if changing the PHP to
while($blablaNode->hasChildNodes()) {
$removedChild = $blablaNode->removeChild($blablaNode->firstChild);
echo "(prefix for removed:".$removedChild->prefix.")";
$magicElement->appendChild($removedChild);
echo "(prefix for added:".$magicElement->lastChild->prefix.")";
}
echo is ...(prefix for removed:)(prefix for added:)(prefix for removed:)(prefix for added:default)...
Many thanks in advance!
P.S. This is sequel to this question thus "Or maybe someone has a much better solution in general for achieving the desirable result [adding magic node and pushing everything in it]" still applies...
Indeed, if "putting default namespace declaration first", as Josh Davis notes, the lookup prefix goes away. +1. But that's it as in the output...
...
<metadata xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#">
...
... the declarations still are there.
A clarification. I'm not the creator of those XML docs. Therefore checking the position of default namespace declaration... even if implemented it still wouldn't give the desirable result. And even if those declarations added by libxml should be there by standard, my task is not to validate conformance, but
- simply put all original childnodes, intact in their content (declarations, names values, attributes etc.), under that extra newly created container.
When you append those children, I guess that libxml looks for the first namespace declaration for "http://www.w3.org/2000/blabla" and finds "blabla". Now if you put your default namespace declaration first, it will find that the default namespace works and it will not prefix those nodes with blabla.
<blabla xmlns="http://www.w3.org/2000/blabla"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:blabla="http://www.w3.org/2000/blabla"
version="1.0">
Update
The issue is entirely cosmetic, but if you want to remove redundant namespace declarations, you can dump and reload your XML:
$xml = $doc->saveXML();
$doc = new DOMDocument;
$doc->loadXML($xml, LIBXML_NSCLEAN);
echo $doc->saveXML();
Attention if you reuse the $doc variable, it doesn't mean that stuff like $blablaNode will remain functional, it won't. The new $doc is a new document.
Oh, and it will also clean up redundant namespaces from the original document, possibly breaking that "keeping it intact" rule.
Oh, and I forgot to mention that you have to explicitely declare which namespace <magic/> is to be created into:
$magicElement = $doc->createElementNS('http://www.w3.org/2000/blabla', 'magic');

Categories