C# LINQ-XML选择节点通用

C# LINQ-XML选择节点通用,c#,xml,linq,xml-parsing,linq-to-xml,C#,Xml,Linq,Xml Parsing,Linq To Xml,我试图剥离XML,只保留我需要的节点 输入XML是 <Employees> <Employee> <EmpId>1</EmpId> <Name>Sam</Name> <Sex>Male</Sex> <Address> <Country>USA</Country> <Zip>95220</

我试图剥离XML,只保留我需要的节点

输入XML是

 <Employees>
  <Employee>
    <EmpId>1</EmpId>
    <Name>Sam</Name>
    <Sex>Male</Sex>
    <Address>
      <Country>USA</Country>
      <Zip>95220</Zip>
    </Address>
    <Address2>
      <Country>UK</Country>
      <Zip>E157JQ</Zip>
    </Address2>
  </Employee>
  <Employee>
    <EmpId>2</EmpId>
    <Name>Lucy</Name>
    <Sex>Female</Sex>
    <Address>
      <Country>USA</Country>
      <Zip>95220</Zip>
    </Address>
    <Address2>
      <Country>UK</Country>
      <Zip>E184JQ</Zip>
    </Address2>
  </Employee>
</Employees>
我从上面得到的输出是

<Employees>
      <Employee>
        <EmpId>1</EmpId>
        <Sex>Male</Sex>
        <Address>
          <Country>USA</Country>
          <Zip>95220</Zip>
        </Address>
        <Address2>
          <Country>UK</Country>
          <Zip>E157JQ</Zip>
        </Address2>
      </Employee>
      <Employee>
        <EmpId>2</EmpId>
        <Sex>Female</Sex>
        <Address>
          <Country>USA</Country>
          <Zip>95220</Zip>
        </Address>
        <Address2>
          <Country>UK</Country>
          <Zip>E184JQ</Zip>
        </Address2>
      </Employee>
    </Employees>

1.
男性
美国
95220
英国
E157JQ
2.
女性
美国
95220
英国
E184JQ
我需要的输出是

<Employees>
  <Employee>
    <EmpId>1</EmpId>
    <Sex>Male</Sex>
    <Address>
     <Zip>95220</Zip>
    </Address>
    <Address2>
      <Country>UK</Country>
    </Address2>
  </Employee>
  <Employee>
    <EmpId>2</EmpId>
    <Sex>Female</Sex>
    <Address>
      <Zip>95220</Zip>
    </Address>
    <Address2>
      <Country>UK</Country>
    </Address2>
  </Employee>
</Employees>

1.
男性
95220
英国
2.
女性
95220
英国
如何查询Address\Zip和Address2\Country我需要这是通用的(因此可以更改字符串保留),所以我无法硬编码节点名称


谢谢

好吧,这取决于你有多希望这是通用的。 这是一种保留当前代码结构的有点粗俗的方法

string keep = @"EmpId,Sex,Address,Address\Zip,Address2,Address2\Country";
string desStr = "Employee";
string[] strArr = keep.Split(',');

var nodesToDelete = xDoc.Root.Descendants(desStr)
                .SelectMany(el => el.Descendants()
                                  .Where(a => 
                                    {
                                        if (a.Parent.Name == desStr)
                                        {
                                            return !strArr.Contains(a.Name.ToString());
                                        }
                                        else
                                        {
                                            return !strArr.Contains(a.Parent.Name + @"\" + a.Name);
                                        }

                                    }));

foreach (var node in nodesToDelete.ToList())
      node.Remove();
正确的方法是保留所有要保留的节点的完整路径。

我的方法:

string keep = "Employees,Employee,EmpId,Sex,Address2,Address,Address.Zip,Address2.Country"; // I can change this format
string[] strArr = keep.Split(',');

    foreach (var node in xDoc.Descendants().ToArray())
    {
        var path = Path(node);
        if (!strArr.Any(path.EndsWith))
        {
            node.Remove();
        }
    }

    var results = xDoc.ToString();
}

private static string Path(XElement x)
{
    if (x.Parent != null)
    {
        return Path(x.Parent) + "." + x.Name;
    }

    return x.Name.ToString();
}

你到底想干什么?您想让XML看起来像地址节点下总是只有Zip,地址2下总是只有国家/地区吗?我试图让它成为输入驱动的,所以如果字符串keep=“EmpId,Sex,Address,Zip,Address2,Country”\ \我可以更改此格式,因此如果是Address\Zip,那么我的XML应该有95220如果是Address\Country,那么我的XML应该是UK您需要输入保持字符串格式吗?因为您尝试执行的操作需要一个类似于树的输入定义,所以解析这样的字符串将很麻烦。不必是字符串格式。它将作为字符串传递,但我可以将其转换为任何格式/对象。问题是您是通过UI从最终用户还是从某些配置接收输入。在配置的情况下,最好使用最终XML格式的XSD;对于用户输入,您要么提供一个方便的UI,要么发明另一种格式,允许您指定节点的层次结构。
string keep = "Employees,Employee,EmpId,Sex,Address2,Address,Address.Zip,Address2.Country"; // I can change this format
string[] strArr = keep.Split(',');

    foreach (var node in xDoc.Descendants().ToArray())
    {
        var path = Path(node);
        if (!strArr.Any(path.EndsWith))
        {
            node.Remove();
        }
    }

    var results = xDoc.ToString();
}

private static string Path(XElement x)
{
    if (x.Parent != null)
    {
        return Path(x.Parent) + "." + x.Name;
    }

    return x.Name.ToString();
}