【问题标题】:Descendants in C# do not give the right valueC# 中的后代没有给出正确的值
【发布时间】:2017-09-15 20:21:34
【问题描述】:

我对使用 C# 的 XML 非常陌生,我有一个 XML 我需要通过父级中的特定子级 我需要获取 id 和调用变量 variables 我这样做但每次都没有通过循环

我是否需要遍历 xml 的所有父级,直到得到我想要的树??

xml

<message xmlns="jabber:client" to="1072@finesse1.dcloud.cisco.com" id="/finesse/api/User/1072/Dialogs__1072@finesse1.dcloud.cisco.com__104Y2" from="pubsub.finesse1.dcloud.cisco.com">
<event xmlns="http://jabber.org/protocol/pubsub#event">
 <items node="/finesse/api/User/1072/Dialogs">
  <item id="460c2d27-c914-4c24-a95f-edf9f8df45c21535">
    <notification xmlns="http://jabber.org/protocol/pubsub">
      <Update>
        <data>
          <dialogs>
            <Dialog>
              <associatedDialogUri></associatedDialogUri>
              <fromAddress>1071</fromAddress>
              <id>18639330</id>
              <mediaProperties>
                <DNIS>1072</DNIS>
                <callType>AGENT_INSIDE</callType>
                <dialedNumber>1072</dialedNumber>
                <outboundClassification></outboundClassification>
                <callvariables>
                  <CallVariable>
                    <name>callVariable1</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable2</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable3</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable4</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable5</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable6</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable7</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable8</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable9</name>
                    <value></value>
                  </CallVariable>
                  <CallVariable>
                    <name>callVariable10</name>
                    <value></value>
                  </CallVariable>
                </callvariables>
              </mediaProperties>
              <mediaType>Voice</mediaType>
              <participants>
                <Participant>
                  <actions>
                    <action>ANSWER</action>
                  </actions>
                  <mediaAddress>1072</mediaAddress>
                  <mediaAddressType>AGENT_DEVICE</mediaAddressType>
                  <startTime>2017-09-15T19:23:36.872Z</startTime>
                  <state>ALERTING</state>
                  <stateCause></stateCause>
                  <stateChangeTime>2017-09-15T19:23:36.872Z</stateChangeTime>
                </Participant>
                <Participant>
                  <actions>
                    <action>UPDATE_CALL_DATA</action>
                    <action>DROP</action>
                  </actions>
                  <mediaAddress>1071</mediaAddress>
                  <mediaAddressType>AGENT_DEVICE</mediaAddressType>
                  <startTime>2017-09-15T19:23:36.609Z</startTime>
                  <state>INITIATED</state>
                  <stateCause></stateCause>
                  <stateChangeTime>2017-09-15T19:23:36.819Z</stateChangeTime>
                </Participant>
              </participants>
              <state>ALERTING</state>
              <toAddress>1072</toAddress>
              <uri>/finesse/api/Dialog/18639330</uri>
            </Dialog>
          </dialogs>
        </data>
        <event>POST</event>
        <requestId></requestId>
        <source>/finesse/api/User/1072/Dialogs</source>
      </Update>
    </notification>
  </item>
 </items>
</event>
</message>

那是 代码

XElement xmlroots = XElement.Parse(parsingNewXML);
//Dialog = xmlroots.Element("Dialog").Value;
var CallVariable = parsingNewXML.Contains("CallVariable");
var startCall = parsingNewXML.Contains("ALERTING");

if (CallVariable == true && startCall == true)
{

    foreach (XElement callID in xmlroots.Descendants("Dialog"))
    {
        DialogID = callID.Element("id").Value;
        //System.Windows.MessageBox.Show(DialogID);
        System.Windows.Application.Current.Dispatcher.BeginInvoke(
        DispatcherPriority.Background,
        new Action(() => ((MainWindow)System.Windows.Application.Current.MainWindow).answerCall.Visibility = Visibility.Visible));
    }
    foreach (XElement callVariables in xmlroots.Descendants("CallVariables"))
    {
        foreach (XElement callVariable in xmlroots.Descendants("CallVariable"))
        {
            list = callVariable.Element("value").Value;
        }
    }
   // state = second.Element("state").Value;
}

【问题讨论】:

  • 你的代码和xml不一致。我说不出你需要什么。 “if”子句没有任何意义。不知道 parsingmsg 指的是什么。使用后代而不是祖先要容易得多。
  • @jdweng 请帮助我我想从这个 xml 中获取 id 我应该怎么做我不知道要编写什么代码来获取 id 我尝试了这段代码但没有帮助我

标签: c# xml linq-to-xml


【解决方案1】:

第一个问题是您只是调用Descendants("Dialog")Descendants("CallVariables") 等。它们在全局命名空间中查找元素 - 但您要查找的所有元素实际上http://jabber.org/protocol/pubsub 的命名空间是因为:

<notification xmlns="http://jabber.org/protocol/pubsub">

当您看到 xmlns="..." 为所有后代设置默认命名空间时。该默认值可以被指定命名空间的元素名称显式覆盖 - 或者它可以由另一个带有xmlns=... 的后代更改。 (您的文档包含多个级别的默认值。)

幸运的是,由于从 stringXNamespace 的隐式转换以及 XName +(XNamespace, string) 运算符,LINQ to XML 可以轻松指定命名空间:

XDocument doc = XDocument.Parse(...);
XNamespace pubsub = "http://jabber.org/protocol/pubsub";
// Find all the descendants with a local name of "Dialog" in the
// namespace specified by the pubsub variable
foreach (XElement dialog in doc.Descendants(pubsub + "Dialog"))
{
    ...
}

作为第二个问题,看看第二个循环:

foreach (XElement callVariables in xmlroots.Descendants("CallVariables"))
{
    foreach (XElement callVariable in xmlroots.Descendants("CallVariable"))
    {
        list = callVariable.Element("value").Value;
    }
}

这样做存在三个问题:

  • 您的文档中没有名为 CallVariables 的元素 - 取而代之的是 callvariables。 XML 区分大小写。
  • 我确定您不希望 every 调用变量元素中的 every 调用变量的组合。相反,我希望是这样的:

    foreach (var callVariables in doc.Descendants(pubsub + "callvariables"))
    {
        // Note use of Elements, not Descendants. You still need
        // the namespace part though...
        foreach (var callVariable in callVariables.Elements(pubsub + "CallVariable"))
        {
            // Do what you want
        }
    }
    
  • 目前您只是替换循环体中的list 变量,这意味着只有循环的最后一次迭代才真正有用。

代码可能还有很多其他问题——解析 XML 然后检查 string 表示是否包含特定字符串(而不是检查特定字符串的存在)似乎很奇怪元素,例如),但那些应该让你开始。

【讨论】:

  • 感谢您回答我正在搜索的内容,我不知道命名空间非常感谢您的解释也请您告诉我为什么有人在问题中给我 -ve 以提高自己下次
【解决方案2】:

我不确定您真正想要什么,但这会将 id 和调用变量提取到对话框对象列表中。如果您想使用 ling-to-xml,您需要先解析 XDocument,然后遍历所需的后代。最后,只需使用另一个循环从调用变量中获取值。

别忘了,要关心最后的异常。

        public class Dialog
        {
            public int id;
            public List<CallVariable> callVariables = new List<CallVariable>();
            public struct CallVariable
            {
                public string name;
                public string value;
            }

        }

        public List<Dialog> GetDialogsFromXml(string xml)
        {
            try
            {
                XDocument doc = XDocument.Parse(xml);
                List<Dialog> dialogs = new List<Dialog>();

                foreach (XElement item in doc.Root.Descendants("{http://jabber.org/protocol/pubsub}Dialog"))
                {

                    int dialogid = int.Parse(item.Element("{http://jabber.org/protocol/pubsub}id").Value);

                    List<Dialog.CallVariable> callvariables = new List<Dialog.CallVariable>();

                    foreach (XElement callVariableNode in item.Descendants("{http://jabber.org/protocol/pubsub}callvariables").FirstOrDefault().Descendants("{http://jabber.org/protocol/pubsub}CallVariable"))
                    {
                        callvariables.Add(new Dialog.CallVariable() { name=callVariableNode.Element("{http://jabber.org/protocol/pubsub}name").Value, value = callVariableNode.Element("{http://jabber.org/protocol/pubsub}value").Value });
                    }

                    dialogs.Add(new Dialog() { id = dialogid, callVariables = callvariables });

                }
                return dialogs;
            }
            catch (Exception e)
            {
                //handle if something goes wrong
                return null;

            }

        }

【讨论】:

    【解决方案3】:

    使用 xml linq。您还需要使用命名空间来获取元素。您可以通过获取 LocalName 来避免命名空间,就像我为对话框所做的那样。 :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XDocument doc = XDocument.Load(FILENAME);
    
                XElement dialogs = doc.Descendants().Where(x => x.Name.LocalName == "dialogs").FirstOrDefault();
                XNamespace ns = dialogs.GetDefaultNamespace();
    
                var results = dialogs.Elements(ns + "Dialog").Select(x => new {
                    id = (int)x.Element(ns + "id"), 
                    associatedDialogUri = (string)x.Element(ns + "associatedDialogUri"),
                    fromAddress = (string)x.Element(ns + "fromAddress"),
                    dnis = (int)x.Descendants(ns + "DNIS").FirstOrDefault(),
                    callType = (string)x.Descendants(ns + "callType").FirstOrDefault(),
                    dialedNumber = (int)x.Descendants(ns + "dialedNumber").FirstOrDefault(),
                    outboundClassification = (string)x.Descendants(ns + "outboundClassification").FirstOrDefault(),
                    callVariables = x.Descendants(ns + "CallVariable").Select(y => new {
                        name = (string)y.Element(ns + "name"),
                        value = (string)y.Element(ns + "value")
                    }).ToList(),
                    participants = x.Descendants(ns + "Participant").Select(y => new
                    {
                        actions = y.Descendants(ns + "action").Select(z => (string)z).ToList(),
                        namemediaAddress = (int)y.Element(ns + "mediaAddress"),
                        mediaAddressType = (string)y.Element(ns + "mediaAddressType"),
                        startTime = (DateTime)y.Element(ns + "startTime"),
                        state = (string)y.Element(ns + "state"),
                        stateCause = (string)y.Element(ns + "stateCause"),
                        stateChangeTime = (DateTime)y.Element(ns + "stateChangeTime")
                    }).ToList(),
                    state = (string)x.Descendants(ns + "state").FirstOrDefault(),
                    toAddress = (int)x.Descendants(ns + "toAddress").FirstOrDefault(),
                    uri = (string)x.Descendants(ns + "uri").FirstOrDefault()
    
                }).ToList();
    
            }
        }
    }
    

    【讨论】:

    • 只是没有任何解释的代码远不如彻底解释您所做的更改和原因。
    • 我没有要求 cmets。我要求解释。您还没有任何解释为什么您需要担心命名空间,例如,这是最重要的方面。 (我也对您采用第一个命名空间的方法提出异议 - 如果文档稍后在不同的命名空间中包含其他 dialogs 元素怎么办?)
    • (我还认为xy 的变量名称不如dialogparticipantvariable 清晰。)
    • "但在这种情况下,元素名称在 x & y 旁边" - 我只能说 I (试图阅读您的代码)必须寻找很长一段时间看他们每次的意思。一眼看不出来。如果你认为你的答案是好的,那么当然,保持原样。我认为解释 OP 在其原始代码中做错了什么会更多更有帮助,而且我认为我对什么是有用的答案有合理的经验。跨度>
    • 不,因为 + 和 add 是同义词,而 x 不提供上下文,而 dialog 提供。您还没有尝试像不知道代码要做什么的人那样阅读您的代码 - 我有,但发现它很难阅读。当然,如果你愿意,你可以忽略反馈,但反馈来自发现代码比它需要的更难阅读的经验。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 2023-03-30
    • 2016-04-15
    • 1970-01-01
    • 2020-06-12
    相关资源
    最近更新 更多