按属性筛选 XML 中的结构

Filtering a structure in XML by attribute

提问人:Pekka 提问时间:11/16/2009 最后编辑:Pekka 更新时间:11/16/2009 访问量:635

问:

我有一个嵌套的简单XML结构,我用PHP的simpleXML加载它。 结构的某些元素包含“上下文”属性。

<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 过滤”。该死的,我印象深刻。

php xpath 简单xml

评论


答:

1赞 Tomalak 11/16/2009 #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赞 Josh Davis 11/16/2009
Wrt 上下文,使用子项来枚举上下文可以使其更易于匹配且更新风险更小。另一方面,它更冗长,因此您可能更喜欢使用命名空间属性,例如<input type="readonly" context:edit_item="1" />
0赞 Pekka 11/16/2009
这两个很好的答案,谢谢,我现在将看看我是如何构建它们的。
1赞 Josh Davis 11/16/2009 #2

如果您必须过滤整个文档,那么 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 表达式的说明:如果值用逗号分隔,请确保只有逗号(没有空格),并在逗号之间将属性的值和要匹配的值括起来。

评论

0赞 Pekka 11/17/2009
仅 xpath 方法不起作用,因为它没有保留我的树结构。我现在正在使用 simpledom,效果很好 - 谢谢。