C# XElement 没有多次为同一个标签获取多个值

Posted

技术标签:

【中文标题】C# XElement 没有多次为同一个标签获取多个值【英文标题】:C# XElement is not getting multiple Values for the same Tag multiple times 【发布时间】:2020-01-13 15:31:51 【问题描述】:

我有这个 .graphml :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
  <!--Created by yEd 3.19.1-->
  <key for="port" id="d0" yfiles.type="portgraphics"/>
  <key for="port" id="d1" yfiles.type="portgeometry"/>
  <key for="port" id="d2" yfiles.type="portuserdata"/>
  <key attr.name="url" attr.type="string" for="node" id="d3"/>
  <key attr.name="description" attr.type="string" for="node" id="d4"/>
  <key for="node" id="d5" yfiles.type="nodegraphics"/>
  <key for="graphml" id="d6" yfiles.type="resources"/>
  <key attr.name="url" attr.type="string" for="edge" id="d7"/>
  <key attr.name="description" attr.type="string" for="edge" id="d8"/>
  <key for="edge" id="d9" yfiles.type="edgegraphics"/>
  <graph edgedefault="directed" id="G">
    <node id="n0">
      <data key="d5">
        <y:UMLClassNode>
          <y:Geometry   x="1301.3333333333333" y="41.0"/>
          <y:Fill color="#FFCC00" transparent="false"/>
          <y:BorderStyle color="#000000" type="line" />
          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false"  horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true"  x="-3.87109375" xml:space="preserve" y="3.0">&lt;&lt;interface&gt;&gt;Employee</y:NodeLabel>
          <y:UML clipContent="true" constraint="" hasDetailsColor="false" omitDetails="false" stereotype="" use3DEffect="true">
            <y:AttributeLabel xml:space="preserve">+name:string
+age:int</y:AttributeLabel>
            <y:MethodLabel xml:space="preserve">getName(value:string):String
getTitle():String
getStaffNo():Number
getRoom():String
getPhone()</y:MethodLabel>
          </y:UML>
        </y:UMLClassNode>
      </data>
    </node>
    <node id="n1">
      <data key="d3" xml:space="preserve"/>
      <data key="d4"/>
      <data key="d5">
        <y:UMLClassNode>
          <y:Geometry   x="1422.0" y="197.0"/>
          <y:Fill color="#FFCC00" transparent="false"/>
          <y:BorderStyle color="#000000" type="line" />
          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false"  horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true"  x="70.661376953125" xml:space="preserve" y="3.0">Customer<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
          <y:UML clipContent="true" constraint="" hasDetailsColor="false" omitDetails="false" stereotype="" use3DEffect="true">
            <y:AttributeLabel xml:space="preserve">+name:string</y:AttributeLabel>
            <y:MethodLabel xml:space="preserve">+getOrder():string
+payOrder(order:string):int</y:MethodLabel>
          </y:UML>
        </y:UMLClassNode>
      </data>
    </node>
    <node id="n2">
      <data key="d3" xml:space="preserve"/>
      <data key="d4"/>
      <data key="d5">
        <y:UMLClassNode>
          <y:Geometry   x="1086.0" y="197.0"/>
          <y:Fill color="#FFCC00" transparent="false"/>
          <y:BorderStyle color="#000000" type="line" />
          <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="13" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false"  horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true"  x="33.54638671875" xml:space="preserve" y="3.0">User<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
          <y:UML clipContent="true" constraint="" hasDetailsColor="false" omitDetails="false" stereotype="" use3DEffect="true">
            <y:AttributeLabel xml:space="preserve">+name:string</y:AttributeLabel>
            <y:MethodLabel xml:space="preserve">getName()</y:MethodLabel>
          </y:UML>
        </y:UMLClassNode>
      </data>
    </node>
  </graph>
  <data key="d6">
    <y:Resources/>
  </data>
</graphml>

这段代码:

public List<Key> AnalyzeNode(XmlReader reader, string filepath)
        
            XDocument doc = XDocument.Load(filepath);
            XNamespace ns = doc.Root.GetDefaultNamespace();

            List<Key> keys = doc.Descendants(ns + "node").Select(x => new Key()
            
                id = (string)x.Attribute("id"),
                baseModel = AnalyzeNodeLabel<UML_Base>(reader, (string)x.Attribute("id"))
            ).ToList();
           return keys;
       
        public T AnalyzeNodeLabel<T>(XmlReader reader, string id) where T : UML_Base
        

            while (reader.Read())
            

                XDocument doc = XDocument.Load(this.filepath);
                XNamespace ns = "http://www.yworks.com/xml/graphml";
                XElement element = doc.Descendants(ns + "NodeLabel").FirstOrDefault();

                string interfaceName = element.Value;

                    if (interfaceName.Contains("&lt;&lt;interface&gt;&gt;") || interfaceName.Contains("interface") || interfaceName.StartsWith("I") && interfaceName.Substring(0, 1).ToUpper().Equals(interfaceName))
                    
                        UML_Interface interfaceModel = new UML_Interface(interfaceName, id);
                        return (T)Convert.ChangeType(interfaceModel, typeof(UML_Interface));
                    
                    if (interfaceName != null && !interfaceName.Contains("&lt;&lt;interface&gt;&gt;") || !interfaceName.Contains("interface") || !interfaceName.StartsWith("I") && !interfaceName.Substring(0, 1).ToUpper().Equals(interfaceName))
                    
                        UML_Class classModel = new UML_Class(interfaceName, id);
                        return (T)Convert.ChangeType(classModel, typeof(UML_Class));
                    
            
            return null;
        

我的问题是 XElement 只获得一个值,但有 3 个 &lt;y:NodeLabel&gt;Tags 具有不同的值。价值观是指文本。但是我的 XElement 对象 (from AnalyzeNodeLabel()) 只是从第一个 &lt;y:NodeLabel&gt; 标记中获取值,我怎样才能添加其他的呢?也许作为列表?或在一个循环后更新值?那可能吗?

【问题讨论】:

使用:List elements = doc.Descendants(yns + "NodeLabel").ToList(); 【参考方案1】:

您明确选择第一次出现的节点:FirstOrDefault() 您必须在循环中选择节点:

foreach (var element in doc.Descendants(ns + "NodeLabel"))

    ...

更新: 我不知道您为什么打开 Xml 文件两次或 XmlReader 发生了什么。 如果您只对节点“node”和“NodeLabel”(可能不止一个)感兴趣,那么这可能会有所帮助:

XNamespace yns = "http://www.yworks.com/xml/graphml";
Dictionary<string, List<string>> keys = new Dictionary<string, List<string>>();
foreach (var node in doc.Descendants(ns + "node"))

    keys[node.Attribute("id").Value] = new List<string>();
    foreach (var nodeLabel in node.Descendants(yns + "NodeLabel"))
    
        keys[node.Attribute("id").Value].Add(nodeLabel.Value);
    


foreach (var entry in keys)

    Console.WriteLine($"Key: entry.Key");
    foreach (var basemodel in entry.Value)
    
        Console.WriteLine($"->basemodel: basemodel");
    

输出是: 键:n0 ->基础模型:>员工 键:n1 ->基础模型:客户 键:n2 ->基本模型:用户

【讨论】:

是的,你是对的,但是当我这样做时,我得到了所有不同的 element.Values 但 id 总是相同的,因为使用 x.Attribute("id") 一个对象的值调用该方法创建的。我也需要其他身份证 如果你选择这个: List keys = doc.Descendants(ns + "node").Select(x => x.Attribute("id").Value).ToList() ;.你得到 n0,n1,n2。 baseModel 怎么样?所有对象都需要 id 和包含 element.value 的 baseModel。 感谢您的更新,但通过您的方法,我得到了每个 id 所有基本模型。所以 n0 --> 有 >Employee,Customer,User 和 n1 ---> 有 >Employee,Customer,User 和 n2 ---> 有 >Employee,Customer,User 例子中的方法不行

以上是关于C# XElement 没有多次为同一个标签获取多个值的主要内容,如果未能解决你的问题,请参考以下文章

如何在c#中使用xelement获取xml节点值

Xelement 扩展空标签

C#:如何从 XElement 中获取名称(带前缀)作为字符串?

在 C# 中使用 XElement 获取 XML 的元素节点值

如何从XElement获取标签

使用 XPathSelectElement 获取 XElement