Как видно из названия, у меня возникает вопрос о разборе XML-тега, который может иметь несколько атрибутов (или вообще ничего), и я ищу предложения о том, как это можно сделать; но во-первых, я думаю, что немного фона в порядке.php SimpleXMLэлемент синтаксический разбор XML-тегов с несколькими «потенциальными» атрибутами
Я работаю на AIML интерпретатор скриптов PHP на основе называется Program O, и я нахожусь в процессе миграции коды из функций замены строки (например, str_replace, preg_replace и т.д.) с использованием РНР встроенных функций SimpleXML , До сих пор почти все функции синтаксического анализа, которые я создал для различных тегов AIML, были полными и работали неплохо, но один тег, в частности, пинает мое сидение, и это тег CONDITION.
В соответствии с AIML tag reference существуют три отдельных «формы» тега: один с атрибутами NAME и (VALUE | CONTAINS | EXISTS), называемый «множественным состоянием», один с атрибутом NAME, называемый «single name list-condition» и окончательная «форма», называемая «условием списка», которая является просто тегом CONDITION, без каких-либо атрибутов. Ссылка на тезис AIML, с которой я связан ранее, имеет примеры для всех трех форм, но с большим количеством слов между ними, поэтому я буду повторять их здесь в контексте с окружающим кодом AIML:
FORM: multi condition теги:
<category>
<pattern>I AM BLOND</pattern>
<template>You sound very
<condition name="gender" value="female"> attractive.</condition>
<condition name="gender" value="male"> handsome.</condition>
</template>
</category>
ФОРМА: список условие тегов:
<category>
<pattern>I AM BLOND</pattern>
<template>You sound very
<condition>
<li name="gender" value="female"> attractive.</li>
<li name="gender" value="male"> handsome.</li>
</condition>
</template>
</category>
ФОРМА: одно имя списка-теги состояние
<category>
<pattern>I AM BLOND</pattern>
<template>You sound very
<condition name="gender">
<li value="female"> attractive.</li>
<li value="male"> handsome.</li>
</condition>
</template>
</category>
В предыдущей версии сценария, что я работаю, только «список-условие» используется форма СОСТОЯНИЯ тега, и в то время как это наиболее распространенная форма используется, он не используется исключительно , поэтому мне нужно уметь приспосабливаться и к другим двум формам. Так что я задал себе вопрос:
Как это можно сделать эффективным образом?
У меня уже есть рабочий код для разбора формы списка условий тега CONDITION, а предварительное тестирование выглядит многообещающим, поскольку оно не вызывает ошибок и, как представляется, создает желаемые ответы (но только для условия списка форма. Остальные 2 формы с ошибками ошибочны по понятным причинам). Функция приведена ниже:
function parse_condition_tag($convoArr, $element, $parentName, $level)
{
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Starting function and setting timestamp.', 2);
$response = array();
$attrName = $element['name'];
if (!empty ($attrName))
{
$attrName = ($attrName == '*') ? $convoArr['star'][1] : $attrName;
$search = $convoArr['client_properties'][$attrName];
$path = ($search != 'undefined') ? "//li[@value=\"$search\"]" : '//li[[email protected]*]';
$choice = $element->xpath($path);
$children = $choice[0]->children();
if (!empty ($children))
{
$response = parseTemplateRecursive($convoArr, $children, $level + 1);
}
else
{
$response[] = (string) $choice[0];
}
$response_string = implode_recursive(' ', $response, __FILE__, __FUNCTION__, __LINE__);
runDebug(__FILE__, __FUNCTION__, __LINE__, "Returning '$response_string' and exiting function.", 4);
return $response_string;
}
trigger_error('Parsing of the CONDITION tag failed! XML = ' . $element->asXML());
}
Я все еще относительно новое для использования функций SimpleXML, так что я вполне может быть что-то очевидное отсутствует. На самом деле, я надеюсь, это точно так. :)
EDIT: Добавление функции, что я, наконец, закончилась с, как и обещал в одном из моих комментариев ниже:
/*
* function parse_condition_tag
* Acts as a de-facto if/else structure, selecting a specific output, based on certain criteria
* @param [array] $convoArr - The conversation array (a container for a number of necessary variables)
* @param [object] $element - The current XML element being parsed
* @param [string] $parentName - The parent tag (if applicable)
* @param [int] $level - The current recursion level
* @return [string] $response_string
*/
function parse_condition_tag($convoArr, $element, $parentName, $level)
{
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Starting function and setting timestamp.', 2);
global $error_response;
$response = array();
$attrName = $element['name'];
$attributes = (array)$element->attributes();
$attributesArray = (isset($attributes['@attributes'])) ? $attributes['@attributes'] : array();
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Element attributes:' . print_r($attributesArray, true), 1);
$attribute_count = count($attributesArray);
runDebug(__FILE__, __FUNCTION__, __LINE__, "Element attribute count = $attribute_count", 1);
if ($attribute_count == 0) // Bare condition tag
{
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Parsing a CONDITION tag with no attributes. XML = ' . $element->asXML(), 2);
$liNamePath = 'li[@name]';
$condition_xPath = '';
$exclude = array();
$choices = $element->xpath($liNamePath);
foreach ($choices as $choice)
{
$choice_name = (string)$choice['name'];
if (in_array($choice_name, $exclude)) continue;
$exclude[] = $choice_name;
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Client properties = ' . print_r($convoArr['client_properties'], true), 2);
$choice_value = get_client_property($convoArr, $choice_name);
$condition_xPath .= "li[@name=\"$choice_name\"][@value=\"$choice_value\"]|";
}
$condition_xPath .= 'li[not(@*)]';
runDebug(__FILE__, __FUNCTION__, __LINE__, "xpath search = $condition_xPath", 4);
$pick_search = $element->xpath($condition_xPath);
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Pick array = ' . print_r($pick_search, true), 2);
$pick_count = count($pick_search);
runDebug(__FILE__, __FUNCTION__, __LINE__, "Pick count = $pick_count.", 2);
$pick = $pick_search[0];
}
elseif (array_key_exists('value', $attributesArray) or array_key_exists('contains', $attributesArray) or array_key_exists('exists', $attributesArray)) // condition tag with either VALUE, CONTAINS or EXISTS attributes
{
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Parsing a CONDITION tag with 2 attributes.', 2);
$condition_name = (string)$element['name'];
$test_value = get_client_property($convoArr, $condition_name);
switch (true)
{
case (isset($element['value'])):
$condition_value = (string)$element['value'];
break;
case (isset($element['value'])):
$condition_value = (string)$element['value'];
break;
case (isset($element['value'])):
$condition_value = (string)$element['value'];
break;
default:
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Something went wrong with parsing the CONDITION tag. Returning the error response.', 1);
return $error_response;
}
$pick = ($condition_value == $test_value) ? $element : '';
}
elseif (array_key_exists('name', $attributesArray)) // this ~SHOULD~ just trigger if the NAME value is present, and ~NOT~ NAME and (VALUE|CONTAINS|EXISTS)
{
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Parsing a CONDITION tag with only the NAME attribute.', 2);
$condition_name = (string)$element['name'];
$test_value = get_client_property($convoArr, $condition_name);
$path = "li[@value=\"$test_value\"]|li[not(@*)]";
runDebug(__FILE__, __FUNCTION__, __LINE__, "search string = $path", 4);
$choice = $element->xpath($path);
$pick = $choice[0];
runDebug(__FILE__, __FUNCTION__, __LINE__, 'Found a match. Pick = ' . print_r($choice, true), 4);
}
else // nothing matches
{
runDebug(__FILE__, __FUNCTION__, __LINE__, 'No matches found. Returning default error response.', 1);
return $error_response;
}
$children = (is_object($pick)) ? $pick->children() : null;
if (!empty ($children))
{
$response = parseTemplateRecursive($convoArr, $children, $level + 1);
}
else
{
$response[] = (string) $pick;
}
$response_string = implode_recursive(' ', $response);
return $response_string;
}
Я подозреваю, что вполне может быть лучше, более элегантный способ (рассказ о моей жизни, действительно), но вышеупомянутое работает по назначению. Любые предложения по улучшению будут с благодарностью приняты и тщательно рассмотрены.
Пожалуйста, обратите внимание здесь, что я не искал кого-то, чтобы «сделать свою домашнюю работу для меня», а, скорее, (не так) нежно подтолкнуть в правильном направлении. Тем не менее, примеры кода по-прежнему приветствуются, но не требуются. :) –