Фильтрация структуры в XML по атрибутам - PullRequest
0 голосов
/ 16 ноября 2009

У меня есть вложенная простая XML-структура, которую я загружаю с помощью PHP SimpleXML. Некоторые элементы структуры содержат атрибуты «context».

<tab context="new_item, edit_item">
  <input type="text" context="new_item">   
  <input type="readonly" context="edit_item">
    <tab context="new_item">
    ...
    </tab>
</tab>

После загрузки мне нужно очистить структуру от всех элементов, которые не принадлежат текущему контексту.

Я мог бы, конечно, пройти через каждый элемент, но, может быть, кто-нибудь знает быстрый, простой SimpleXML способ - возможно, с XPath - для соответствующей фильтрации структуры?

Обратите внимание, что "context" - это список значений, разделенных запятыми, однако я мог бы изменить его на более разбираемый вид:

context_new_item="yes" context_edit_item = "no"

при необходимости.

Я сам сейчас просматриваю документацию simpleXML, но это не самая обширная часть документации PHP ...

Обновление : этому посту едва исполнилось 13 минут, и он уже 2-й в Google по показателю "симплексная фильтрация". Блин, я впечатлен.

Ответы [ 2 ]

1 голос
/ 16 ноября 2009

Если вам нужно отфильтровать весь документ, тогда XPath - это путь. Проблема в том, что SimpleXML не может удалить произвольные узлы, подобные этой, поэтому вам нужно преобразовать их в DOM , а затем использовать parentNode-> removeChild ()

Я поддерживаю библиотеку, которая делает подобные вещи, SimpleDOM . Вот как я это сделаю:

include 'SimpleDOM.php';

$tab = simpledom_load_string(
    '<tab context="new_item,edit_item">
      <input type="text" context="new_item" />
      <input type="readonly" context="edit_item" />
        <tab context="new_item">
        ...
        </tab>
    </tab>'
);

$context = 'new_item';

// will match ",new_item," to ",new_item,edit_item,"
$tab->deleteNodes('//*[contains(concat(",", @context, ","), ",' . $context . ',")]');

echo $tab->asXML();

Обратите внимание, что не удалит корневой узел, так как это сделает документ недействительным. Если вы не хотите зависеть от внешней библиотеки, не стесняйтесь взглянуть на исходный код и скопировать / вставить то, что вам нужно.

Примечание о выражении XPath: если значения разделены запятыми, убедитесь, что нет ничего, кроме запятых (без пробелов), и заключите между запятыми как значение атрибута, так и значение, которому вы соответствуете.

1 голос
/ 16 ноября 2009

Если в вашем PHP-приложении есть значение «context», вы можете выбрать:

$context = "new_item";
$xpath = "//*[not(contains(concat(',', normalize-space(@context), ','), ',$context,'))]";

Теперь вы выбрали все, что не в нужном контексте.

Теперь, если у вас была эта структура:

<tab context="new_item, edit_item">
  <context name="new_item" />
  <context name="edit_item" />
  <input type="text">
    <context name="new_item" />
  </input>
  <input type="readonly">
    <context name="edit_item" />
  </input>
  <tab>
    <context name="new_item" />
    ...
  </tab>
</tab>

Вы можете сделать это проще и эффективнее:

$context = "new_item";
$xpath = "//*[not(context[@name='new_item'])]";

Вы также можете использовать выделенные атрибуты, если количество возможных контекстов ограничено.

$context = "new_item";
$xpath = "//*[not(context_$context = 'yes')]";
...