XML namespaces and writing XML to files

Unit: 4 out of 10

To avoid overlapping XML structures with the same name, but with different structures of a document, we can use, among others, namespaces. Namespaces ensure the contextual integrity of the data within them.

E.g:

1
2
3
4
5
6
7
8
9
10
11
12
<root>
<card>
    <name>visa virtuon</name>
    <name>visa elektron</name>
    <name>master card</name>
</card>
<card>
    <manifacturer>msi</manifacturer>
    <manifacturer>asus</manifacturer>
    <manifacturer>intel</manifacturer>
</card>
</root>

 

This XML document contains card data, but its elements actually contain completely different data types. One element contains payment cards and the other element contains graphics cards. However, the parser will not be able to differentiate between these types and all data will be treated identically. Therefore, these two types of data can be separated by namespaces: 

1
2
3
4
5
6
7
8
9
10
11
12
<root>
<credit:card xmlns:credit="creditCards">
    <credit:name>visa virtuon</credit:name>
    <credit:name>visa electron</credit:name>
    <credit:name>master card</credit:name>
</credit:card>
<graphic:card xmlns:graphic="graphicCards">
  <graphic:manufacturer>msi</graphic:manufacturer>
  <graphic:manufacturer>asus</graphic:manufacturer>
  <graphic:manufacturer>intel</graphic:manufacturer>
</graphic:card>
</root>

We see that some components have been added to the previous XML document.

  • Each element (subelement) contains a prefix separated by a colon from the element name. In the first set the prefix is ​​payment and in the second set the prefix is ​​graphic. These allow us to put the desired elements in the desired namespaces.
  • xmlns:credit=”creditCards” – This is the namespace declaration: xmlns: (the keyword that designates the beginning of the namespace declaration), credit (the prefix of the namespace (this prefix must be respected when we write the names of the elements)), =“creditCards”. (The namespace identifier. It doesn’t matter what you write here, as long as it’s unique at the document level, because later we’ll refer to the namespace based on this word/name. Most often, as the namespace identifier , a web location where the description of this namespace is located is entered.)

Reading the namespace can be done in different ways. Using SimpleXML, this process is very simple:

1
2
3
4
...
$graphicCards = $xml->children('graphicCards'); 
foreach ($graphicCards>card>manufacturer as $graphicCard)
    echo $graphicCard . "<br>";

 

If we assume that the $xml variable contains the XML document from the previous example, we can extract all the elements of a namespace using the children() method. This method returns all sub-elements of an element, but can also accept an optional parameter – namespace. In this case, to return all subelements, one condition will have to be met – the identity of the namespace declared as a parameter with one of the existing namespaces.

Apart from inside elements, namespaces can also be defined in the root of the document itself. In this case, we set all the namespace definitions one by one as separate attributes of the root element:

1
2
3
4
5
6
7
8
9
10
11
12
<root xmlns:credit="creditCards" xmlns:graphic="graphicCards">
<credit:card>
    <credit:name>visa virtuon</credit:name>
    <credit:name>visa electron</credit:name>
    <credit:name>master card</credit:name>
</credit:card>
<graphic:card>
  <graphic:manufacturer>msi</graphic:manufacturer>
  <graphic:manufacturer>asus</graphic:manufacturer>
  <graphic:manufacturer>intel</graphic:manufacturer>
</graphic:card>
</root>

 

Writing XML documents to files

We can freely say that by reading and parsing the XML document or by creating our own document, we did the hardest part of processing it. Another part, usually simpler, is issuing it, or enrolling in a system. Most often, this will be a local file system.

asXML() and save()

We have already used the asXML() method of the SimpleXMLElement class to output the XML to the page. In the same way, we can also output XML to the file:  

$xml->asXML(“myFile.xml”);

This is pretty simple to do, but of course it only works when we’re only handling the SimpleXML object.

If we manage the DOMDocument object (we will deal with this library in future lessons), we will use the save() method:

$dom->save(“myFile.xml”);

Manual writing

Sometimes we will create the XML document without using specialized classes. Simply, by sequentially passing through a source and creating the XML construction by string. The final result of this process will be a string that will contain the XML structure.

Such a string can be output in a standard way:

  • via buffered input:

file_put_contents(“myFile.xml”,$xmlString);

1
2
3
4
5
6
7
8
9
10
11
12
$file=fopen("myFile.xml","w");
$row='<?xml version="1.0" encoding="utf-8"?>‘;
$row.='<root>';
fwrite($file,$row);
  foreach($stream as $streamRow)
{
$row = "<myElement>" . $streamRow . "</myElement>";
fwrite($file, $streamRow);
}
$row='</root>';
fwrite($file,$row);
fclose($file);

The last two input methods are quite linear and do not really take into account the formatting of the output, so we have to insert the newlines manually if we want the XML to be well formatted on the output:

$rowI = “<myElement>” . $streamRow . “</myELement>\n\r”;

The escape characters \n and \r mark a new line in text. If Windows OS is used, both (n and r) must be entered, if Linux OS is used, only n is sufficient, and if Mac OS is used, only r is sufficient. Both signs work on all systems .

 

If we use the asXML() method along with the filename in it, like: asXML(\\\\”file.xml\\\\”), the result of the execution will be:

Exercise

In the exercise in the previous lesson, add namespaces for all messages saved in the XML document so that we distinguish incoming and outgoing messages by namespace.

Note:

The solution to the task can be found in the video materials of this lesson.