按属性过滤XML中的结构

时间:2009-11-16 14:15:26

标签: php xpath simplexml

我有一个嵌套的简单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分钟,已经在Google上获得第二名“simplexml过滤”。该死的,我印象深刻。

2 个答案:

答案 0 :(得分:1)

如果您在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')]";

答案 1 :(得分:1)

如果你必须过滤整个文档,那么XPath就是你要走的路。问题是SimpleXML无法删除这样的任意节点,所以你必须convert them to DOM然后使用parentNode-&gt; 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表达式的注释:如果用逗号分隔值,请确保除了逗号(没有空格)之外没有其他内容,并将属性的值和您在逗号之间匹配的值括起来。