I am writing a class to read content of an xml with mysql-like syntax (of course it not completly the same syntax and I ignore many things, just want to have some basics).
First of all, statements look like:
"SELECT name passwd FROM table WHERE id = 1 and description = 'desc'"
Some basic rules:
I haven't done anything but the method for the select statement. I explode the statement, sort it into an array and then try to translate it to DOMXpath
It works if there's no WHERE. But I'm struggling with the where-clauses (here what I have done so far:)
statement: "SELECT name pw FROM user WHERE id = '1' and description = 'test or test2'"
the array looks like:
array(4) {
["type"]=>
string(6) "SELECT"
["searchFields"]=>
array(2) {
["searchField0"]=>
string(4) "name"
["searchField1"]=>
string(2) "pw"
}
["tableName"]=>
string(4) "user"
["comparer"]=>
array(2) {
["where0"]=>
array(3) {
["field"]=>
string(2) "id"
["operator"]=>
string(1) "="
["value"]=>
string(3) "'1'"
}
["where1"]=>
array(4) {
["splitTag"]=>
string(3) "and"
["field"]=>
string(11) "description"
["operator"]=>
string(1) "="
["value"]=>
string(15) "'test or test2'"
}
}
}
How I'm trying to convert the statement to Xpath with the following code:
for ($i = 0; $i < count($arrQuery['searchFields']); $i++) {
$conditions = "";
foreach ($arrQuery['comparer'] as $value) {
switch (count($arrQuery['comparer'])) {
case 1:
$conditions .= '//parent::content[@name="'.$value['field'].'" and text()='.$value['value'].']';
break;
case 2:
if (!isset($value['splitTag']) || $value['splitTag'] == "and") {
$conditions .= '//parent::content[@name="'.$value['field'].'" and text()='.$value['value'].']';
break;
} else {
//$conditions .= 'content[@'.$value['field'].' and text()='.$value['value'].']//parent::*';
}
break;
}
}
$xpathquery = '//datarange[@name="'.$arrQuery['tableName'].'"]'.$conditions.'//content[@name="'.$arrQuery['searchFields']['searchField'.$i].'"]';
$nodeList = $this->xpath->query($xpathquery);
foreach ($nodeList as $node) {
$arrContent['searchField'.$i][] = $node->nodeValue;
}
}
My first Point is: if the condition of the if-clause in case 2 is confirmed, the created xpath isn't working (might be problem with parent or my logic)
My second Point is: I still have no idea how to handle the case that the condition doesn't match and $value['splitTag'] is "or". If anyone has a hint how to solve that, I would be very thankfull.
/EDIT: Ok, thanks for the tip, here's an example of my xml:
<database>
<datarange id="user">
<dataset id="0">
<content name="id">
1
</content>
<content name="description">
test or test2
</content>
<content name="name">
Name
</content>
<content name="pw">
Passwort
</content>
</dataset>
<dataset id="1">
<content name="name">
Name2
</content>
<content name="pw">
Passwort2
</content>
</dataset>
</datarange>
<datarange id="config">
<dataset id="0">
<content name="type">
command
</content>
<content name="name">
lab
</content>
<content name="type">
request
</content>
<content name="target">
target_name
</content>
<content name="desc">
Address Book
</content>
</dataset>
</datarange>
</database>
Given your input document and the query: SELECT name pw FROM user WHERE id = '1' and description = 'test or test2
you will have to build yourself the following XPath to get to the dataset
node that has the values you need:
//datarange[@id = 'user']/dataset
[normalize-space(content[@name = 'id']) = '1']
[normalize-space(content[@name = 'description']) = 'test or test2']
This one will give you the dataset
node that you can then run the following on:
normalize-space(content[@name = 'name'])
to get the name
and:
normalize-space(content[@name = 'pw'])
Here's a simple XSLT to test it:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="//datarange[@id = 'user']/dataset
[normalize-space(content[@name = 'id']) = '1']
[normalize-space(content[@name = 'description']) = 'test or test2']"/>
</xsl:template>
<xsl:template match="dataset">
name: <xsl:value-of select="normalize-space(content[@name = 'name'])"/>
pwd: <xsl:value-of select="normalize-space(content[@name = 'pw'])"/>
</xsl:template>
</xsl:stylesheet>
When applied to your input document it will produce:
name: Name
pwd: Passwort
You can now factor it into your query SQL-like-to-XPath engine.
One more thing though. If you can upgrade to XPath 2.0 you may want to try the conditional and quantified expressions to make your XPath more query-like. And who knows, maybe you won't need a SQL-like syntax to begin with. Plus there's XQuery.