【问题标题】:without knowing the structure of an xdoc, select elements whose immediate value is在不知道 xdoc 结构的情况下,选择立即值为
【发布时间】:2015-07-28 03:32:05
【问题描述】:

更新: 我完全把问题简单化了,把每个人都误入歧途了。这是 actual 问题:我正在尝试获取其值与正则表达式匹配的元素。我重写了问题...

给定一个我不知道结构的 XDocument,如何选择所有值与正则表达式匹配的元素?

例如:

<html>
    <head></head>
    <body>
        <table>
            <tr>
                <td>{{ var1 }}</td>
                <td>{{ var2 }}</td>
            </tr>
            <tr>
                <td>{{ var3 }}</td>
                <td>{{ var4 }}</td>
            </tr>
        </table>
    </body>
</html>

我会得到 html、body、table、tr 和四个 td 元素的结果。如何选择值与此正则表达式匹配的所有元素并仅返回 td 元素

private Regex _placeholderRegex = new Regex("({{.+?}})");

public string GetParsedDocument(...)
{
    var placeHolders = _template
        .Descendants()
        .Where(d => _placeholderRegex.IsMatch(d.Value));

    // more stuff
    return null;
}

我最终得到一个结果,每个元素都是我正在寻找的元素的祖先...

所以现在我想了想,我发现它只是查看每个元素的全部内容,并在其中任何地方包含匹配项时选择它。所以我想只需要找到一种方法来缩小范围。

【问题讨论】:

  • 我认为您正在寻找文本,而不是价值。 (请注意,最好将 HTML 显示为 XML 的示例,但是...)
  • 我实际上是在尝试构建一个模板解析器来创建 html 电子邮件。我已将 html 文档解析为 XDocument 仅用于操作目的,XDoc 未公开。此外,Text 似乎不是可用的属性。
  • @Sinaesthetic can't reproduce the problem(只有 2 个元素按预期返回)
  • Ack...好吧,那是我的错。我试图简化问题并最终掩盖了它。事实是我正在使用正则表达式来进行匹配。我会更新我的问题。

标签: c# linq linq-to-xml


【解决方案1】:

这是一种可能的方式:

var placeHolders = from d in mydoc.Descendants()
                   where d.DescendantNodes()
                          .OfType<XText>()
                          .Any(o => o.Parent == d && _placeholderRegex.IsMatch(o.Value))
                   select d;

以上代码的工作原理是检查是否有任何文本节点,即当前节点d (Parent == d) 的直接子节点,其值与正则表达式模式匹配。

这是demo 的工作示例:

var xml = @"<html>
    <head></head>
    <body>
        <table>
            <tr>
                <td>{{ var1 }}</td>
                <td>{{ var2 }}</td>
            </tr>
            <tr>
                <td>{{ var3 }}</td>
                <td>{{ var4 }}</td>
            </tr>
        </table>
    </body>
</html>";
var mydoc = XDocument.Parse(xml);
var _placeholderRegex = new Regex("({{.+?}})");
var placeHolders = from d in mydoc.Descendants()
                   where d.DescendantNodes()
                          .OfType<XText>()
                          .Any(o => o.Parent == d && _placeholderRegex.IsMatch(o.Value))
                   select d;
foreach (var placeHolder in placeHolders)
{
    Console.WriteLine(placeHolder.Value);
}

输出:

{{ var1 }}
{{ var2 }}
{{ var3 }}
{{ var4 }}

【讨论】:

    【解决方案2】:

    如果我理解正确的话:

    1. 如果只有 td 元素,将 .Descendants() 替换为 .Descendants("td")

      var placeHolders = mydoc
                  .Descendants("td")
                  .Where(d => _placeholderRegex.IsMatch((string)d))
                  .Select(x => (string)x);
      

    链接:https://dotnetfiddle.net/eoDVWH

    1. 或者,检查子元素是否存在:

      var placeHolders = mydoc
                  .Descendants()
                  .Where(d => !d.HasElements && _placeholderRegex.IsMatch((string)d))
                  .Select(x => (string)x);
      

    链接:https://dotnetfiddle.net/FEwSf3

    【讨论】:

      【解决方案3】:

      您可以将!d.Elements().Any() 添加到您的谓词中以仅获取没有任何子元素的元素:

      var placeHolders = _template
          .Descendants()
          .Where(d => !d.Elements().Any() && _placeholderRegex.IsMatch((string)d))
          .ToList();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-08-14
        • 2018-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多