A lightweight XML parsing server implemented in C without using any third-party libraries or STL containers such as vector, queue, or list.
The project consists of two independent processes:
-
XML Server Process
- Parses and maintains an XML document in memory.
- Handles read and write requests from clients.
- Persists modifications back to disk.
-
Client Process
- Establishes IPC communication with the server.
- Provides an interactive interface to query and update XML elements.
Implement an XML server that allows retrieval and modification of XML data using dot notation.
Examples:
GET("planes_for_sale.ad.year");
// Returns: 1977
SET("planes_for_sale.ad.year", 1900);
// Updates year to 1900 and saves XML.
GET("planes_for_sale.ad.previous.0");
// Returns: 1<year>1977</year><location>
<city>Rapid City</city>
<state>South Dakota</state>
</location><previous>[1 2 3 4 5]</previous>Arrays are an extension introduced specifically for this assignment and are not part of standard XML.
<!-- This is a comment -->Comments are ignored by the parser.
Since XML does not provide explicit type information, the parser internally has to store the type of each value.
Supported types:
- Integer
- Floating point numbers
- String
- Arrays of numbers
- Arrays of strings
Nested XML elements can be accessed using . separators.
Example XML:
<planes_for_sale>
<ad>
<location>
<city>Rapid City</city>
</location>
</ad>
</planes_for_sale>Query:
GET("planes_for_sale.ad.location.city")Result:
Rapid City
Array indexing:
GET("planes_for_sale.ad.previous.3")Result:
4
The implementation follows the restrictions specified in the project:
-
XML tags do not contain attributes.
Unsupported:
<test type="A">1</test>
-
Every tag contains either:
- another XML tag
- a primitive value
- an array
-
Maximum nesting level is limited to 5.
-
Duplicate tags under the same parent are not allowed.
The server returns an error when:
- A tag does not exist.
- An array index is out of bounds.
- The query path is invalid.
- XML syntax is malformed.
-
No third-party libraries.
-
No XML parsing libraries.
-
No STL containers:
vectorqueuelist
All data structures are implemented manually.
Interprocess communication mechanism is implementation dependent.
Examples:
- UNIX Domain Sockets
- Named Pipes (FIFO)
- Shared Memory
- TCP Socket
+------------------+
| XML Client |
+------------------+
|
| IPC
|
+------------------+
| XML Server |
+------------------+
|
|
v
+------------------+
| XML File |
+------------------+
The server loads the XML file into memory during startup. Any modification through SET() immediately updates the in-memory representation and writes the updated XML back to disk.
<?xml version="1.0" encoding="utf-8"?>
<planes_for_sale>
<ad>
<year>1977</year>
<make>43</make>
<model>Skyhawk</model>
<color>Light blue and white</color>
<description>
New paint, nearly new interior,
685 hours SMOH,
full IFR King avionics
</description>
<price>23495</price>
<seller>Skyway Aircraft</seller>
<location>
<city>Rapid City</city>
<state>South Dakota</state>
</location>
<previous>[1 2 3 4 5]</previous>
</ad>
</planes_for_sale>> GET planes_for_sale.ad.year
1977
> SET planes_for_sale.ad.year 1900
OK
> GET planes_for_sale.ad.previous.2
3
Developed and tested on Linux using POSIX APIs.
The XML document is parsed into an in-memory tree structure.
Each node stores:
- Tag name
- Value (if any)
- Data type information
- Pointers to child nodes
- Pointer to parent node
Queries are resolved by tokenizing the dot notation and traversing the tree node by node until the requested element is found.
The server and client communicate using two POSIX Named Pipes (FIFO):
pipe_to_server : Client → Server requests
pipe_to_client : Server → Client responses
Using two pipes allows full request-response communication while keeping the implementation simple.
Build both parser_server and client separately.
gcc parser_server.c -o parser_server
gcc client.c -o clientRun both server and client in separate terminals.
-
Start server first (with xml path):
./parser_server <xml_file>
-
On another terminal, run client (with pipe information)
./client <server_pipe> <client_pipe> i.e. ./client /tmp/pipe_to_server /tmp/pipe_to_client
Use ctrl+c to stop the server or client.
-
The client provides an interactive shell.
- Available commands:
- get : Retrieve a value from the XML server
- set : Update a value in the XML server
- help : Displays available commands
- exit : Exit the client
- Available commands:
-
Now for command type:
- get
- You need to enter query in this format (tag1.tag2.tag3)/(tag1.tag2.tag3.2 // for array position query) {press enter}
- Output is the value and data type of the value
- set
- You need to enter query in this format (tag1.tag2.tag3)/(tag1.tag2.tag3.2 // for array position query) {press enter}
- Then enter the value to be set {press enter}
- Output should be success or failure
- You need to enter query in this format (tag1.tag2.tag3)/(tag1.tag2.tag3.2 // for array position query) {press enter}
- NOTE: You will get error message if anything goes wrong during requests
- get
- XML document is well-formed.
- Maximum nesting depth is five levels.
- Tags are unique within the same parent.
- Arrays cannot contain nested XML tags.
- Arrays contain only primitive values.
- Support XML attributes.
- Support repeated tags.
- Remove nesting depth limitation.
- Add concurrent client handling.
- Add schema validation.
- Support larger XML documents using streaming parsing.