0

我正在编写一个类来读取具有类似 mysql 语法的 xml 的内容(当然它的语法不完全相同,我忽略了很多东西,只是想有一些基础知识)。

首先,语句看起来像:

"SELECT name passwd FROM table WHERE id = 1 and description = 'desc'"

一些基本规则:

  • 一切之间必须有一个空格
  • 在“WHERE”之后不超过两次比较

除了选择语句的方法,我什么都没做。我分解语句,将其排序为一个数组,然后尝试将其转换为 DOMXpath

如果没有 WHERE,它就可以工作。但是我正在为 where-clauses 苦苦挣扎(这是我到目前为止所做的事情:)

语句:“从用户 WHERE id = '1' 和描述 = 'test 或 test2' 中选择名称 pw”

数组看起来像:

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'"
    }
  }
}

我如何尝试使用以下代码将语句转换为 Xpath:

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;
    }
}

我的第一点是:如果案例 2 中的 if 子句的条件得到确认,则创建的 xpath 不起作用(可能是父级或我的逻辑有问题)

我的第二点是:我仍然不知道如何处理条件不匹配且 $value['splitTag'] 为“或”的情况。如果有人提示如何解决这个问题,我将非常感激。

/编辑:好的,感谢您的提示,这是我的 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>
4

1 回答 1

1

给定您的输入文档和查询:SELECT name pw FROM user WHERE id = '1' and description = 'test or test2您必须自己构建以下 XPath 才能到达dataset具有所需值的节点:

//datarange[@id = 'user']/dataset
      [normalize-space(content[@name = 'id']) = '1']
      [normalize-space(content[@name = 'description']) = 'test or test2']

这将为您提供一个dataset节点,然后您可以在该节点上运行以下命令:

normalize-space(content[@name = 'name'])

得到name和:

normalize-space(content[@name = 'pw'])

这是一个简单的 XSLT 来测试它:

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

当应用于您的输入文档时,它将产生:

name: Name
pwd: Passwort

您现在可以将其纳入查询 SQL-like-to-XPath 引擎。

不过还有一件事。如果您可以升级到 XPath 2.0,您可能想尝试条件表达式和量化表达式,以使您的 XPath 更像查询。谁知道呢,也许您一开始就不需要类似 SQL 的语法。另外还有XQuery

于 2012-05-26T17:05:40.297 回答