【问题标题】:How can C# look return an XML node with a specific element value?C# 外观如何返回具有特定元素值的 XML 节点?
【发布时间】:2013-04-22 13:29:44
【问题描述】:

一个商业应用程序使用 XML 来保存它使用的变量列表。我无法控制 XML 的格式。我可以使用任何版本的.Net

尝试编写更简单的代码来将UserVar 节点分配给我创建的对象。现在我找到包含所有单个 UserVars 的 UserVars 部分的节点,遍历每个 UserVar 寻找元素“名称”,然后查看它是否与我想要的变量名称匹配。

例如,我想要变量“已更改”,我将获得一个 AcmeVar 对象(我的创建),其属性 NameWidth 设置为“已更改”和 1。但我必须手动遍历代码。

似乎我正在努力做到这一点。理想情况下,我喜欢使用 Linq 返回具有匹配元素名称的 UserVar 节点。 Stackoverflow 上的类似问题没有遵循类似的模式,或者至少不是我所看到的。并非所有变量都使用所有元素类型。

示例:XML

<?xml version="1.0" encoding="UTF-8"?>
<Application>
  <Vars>
    <UserVars>
      <UserVar>
        <Name>"Quantity"</Name>
        <Width>4</Width>
        <VarValue>"1"</VarValue>
      </UserVar>
      <UserVar>
        <Name>"Printers"</Name>
        <Width>255</Width>
      </UserVar>
      <UserVar>
        <Name>"Changed"</Name>
        <Width>1</Width>
      </UserVar>
      <UserVar>
        <Name>"Weight"</Name>
        <VarValue>"450.1"</VarValue>
      </UserVar>
    </UserVars>
  </Vars>
</Application>

当前代码:

public static bool GetVariable(string xmlDocNm, string varName, out AcmeVariable acmeVar)
{
  // Returns true if found without error

  bool result = false;
  acmeVar = new AcmeVariable ();

  try {
    XPathDocument doc = new XPathDocument(xmlDocNm);
    XPathNavigator nav = doc.CreateNavigator();

    // Compile a standard XPath expression
    XPathExpression expr;
    expr = nav.Compile(AcmeConst.XPathInternalVariable);
    XPathNodeIterator iterator = nav.Select(expr);

    // Iterate on the node set
    try {
      bool variableFound;
      bool skipNode;

      char[] CharsToTrim = { '\"' }; // 
      while (iterator.MoveNext()) {
        variableFound = false;
        skipNode = false;
        XPathNavigator nav2 = iterator.Current.Clone();
        if (nav2.MoveToFirstChild()) {
          // nav2 points to the first element in an UserVar Node
          acmeVar = new AcmeVariable ();               //Start with a fresh Acme Variable

          if (nav2.LocalName == AcmeConst.AttrName) {
            variableFound = true;
            skipNode = nav2.Value.Trim(CharsToTrim) != varName;
          }
          if (!skipNode) {
            AssignXMLNavNodetoAcmeVar(nav2, acmeVar);
            while (nav2.MoveToNext() && !skipNode) {
              if (nav2.LocalName == AcmeConst.AttrName) {
                variableFound = true;
                skipNode = nav2.Value.Trim(CharsToTrim) != varName;
              }
              AssignXMLNavNodetoAcmeVar(nav2, acmeVar);
            }
          }
        }
        if (variableFound && !skipNode) {
          result = true;
          break; //We have found the variable and collected all elements
        }
        else {
          acmeVar = null;
        }
      }
    }
    catch (Exception ex) {
      MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
      acmeVar = null;
      result = false;
    }
  }
  catch (Exception ex) {
    MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
    acmeVar = null;
    result = false;
  }

  return result;
} 

【问题讨论】:

    标签: c# .net xml-parsing linq-to-xml


    【解决方案1】:

    试试这个:

    var queryValue = "Quantity";
    var xDoc = XDocument.Load(@"UserVars.xml");//This is your xml path value
    
    var userVar = xDoc.Descendents("UserVar").Where(x => x.Element("Name").Value == queryValue )
                      .FirstOrDefault();
    
    var name     = userVar.Element("Name").Value ?? string.Empty;
    var width    = userVar.Element("Width").Value ?? string.Empty;
    var varValue = userVar.Element("VarValue").Value ?? string.Empty;
    

    我只是想对您的 XML 进行评论,尤其是在 &lt;Name&gt;"Quantity"&lt;/Name&gt; 元素值被 "" 括起来的部分

    但是如果你没有绑定xml,你只需要转义那些"。例如。 var queryValue = @""Quantity"";

    【讨论】:

    • 关于引号,是的,这就是它们具有字符串值的方式。该文件来自商业产品,因此我必须忍受它。
    • @Rich Shealer 我还发现您的 XML 构建存在错误。查看元素 UserVar 的元素 Name 值为 "Quantity". That should be 4, not 4`
    • 这基本上有效。如果元素不存在,我会得到一个异常而不是 string.empty。由于我没有提供到 UserVar 部分的路径,因此这不会区分是否存在 UserVar 的类似部分。在这种情况下不是问题,只是想了解一下。
    • 是的 - 我会解决的。当我在做一个极简主义的例子时发生了。
    • 是的。然后如果你想处理异常,只需删除?? 运算符即可。
    【解决方案2】:

    假设您的键是名称,并且所有节点都将包含它,那么这应该可以工作:

    string valImLookingFor = "\"Changed\"";
    XDocument doc = XDocument.Load("file"); // or XDocument doc = XDocument.Parse(xmlString);
    
    var node = doc.Descendants("UserVar").Where(x => x.Element("Name").Value == valImLookingFor).First();
    

    这应该让你得到你的节点,然后你可以提取你需要的子节点值。

    【讨论】:

    • 这类似于 lexeRoy 的回答。关于这两个答案的一件事是它不返回 XmlNode。我需要看看是否可以使用返回的 Xelement 删除现有节点。
    • 更准确地说,他的答案与我早于他发布的答案相似(按最旧排序)。它不返回 XmlNode,因为这是在将 Linq 引入 Xml 之前在 C# 中执行 XML 的较旧方式。是的,您可以使用 XElement 删除元素(比使用 XmlNode 更容易)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-07
    • 1970-01-01
    • 2011-07-06
    相关资源
    最近更新 更多