C#外观如何返回具有特定元素值的XML节点?

时间:2013-04-28 23:37:34

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

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

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

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

好像我正在努力做到这一点。理想情况下,我很乐意使用Linq返回具有匹配元素Name的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;
} 

2 个答案:

答案 0 :(得分:3)

试试这个:

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发表评论,尤其是在<Name>"Quantity"</Name>

附加""元素值的部分

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

答案 1 :(得分:1)

假设您的密钥是Name,并且所有节点都包含该密钥,那么这应该有效:

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();

那应该是你的节点,然后你可以提取你需要的子节点值。