【问题标题】:What is wrong with my use of XPath in C#?我在 C# 中使用 XPath 有什么问题?
【发布时间】:2018-11-06 10:36:06
【问题描述】:

我正在尝试在 C# 应用程序中进行一些抓取。

我正在尝试访问以下页面上的 4 条信息: https://smstestbed.nist.gov/vds/current

  • 创建时间
  • 可用性
  • 线性 X 和 Y 坐标

以下功能是我从远程加工工具轮询实时数据馈送的地方。 我遇到的问题是,虽然我能够将“CreationTime”打印到终端,但我的 XPath 使用非常笨拙,而且就This Link 而言,我似乎应该能够在两行中做我正在做的事情在我的评论之后

"//这应该是访问数据的更好方法,但由于某种原因第二行失败"

不幸的是,我得到 AvailabilityNode 为 Null。

public static void PollNIST()
    {
        string NISTSourceURL = "https://smstestbed.nist.gov/vds/current";  // Gives us a human friendly reference to the HTM
        //-------------------------------- Current (mostly) Working Version---------------------------------------------------------------------------------
        // Retrieve raw HTML
        var NISTTargetURL = NISTSourceURL;
        var NISTHttpClient = new HttpClient();
        var NISTXMLRaw = NISTHttpClient.GetStringAsync(NISTTargetURL);  // We now have all of the HTML / XML Data as a raw string
                                                                        //Console.WriteLine(MazXMLRaw.Result);                   // Prints the resulting HTML to a terminal as a debug tool    (Works)   
        XmlDocument CurNISTXML = new XmlDocument();               // Generate Blank XML Doc
        CurNISTXML.LoadXml(NISTXMLRaw.Result);                     // This (".result") passes the actual string?, should then be loaded into new XML file

        var elementHeader = CurNISTXML.GetElementsByTagName("Header");
        var curNISTHeader = elementHeader.Item(0);
        var creationTime = curNISTHeader.Attributes[0];  // We actually have the creationTime            
        string CurNISTTime = creationTime.InnerText; ; //      //*[@id="mtconnect content"]/ul/li[1]

        //This should be a far better way of accessing the data but for some reason the second line fails
        XmlNode AvailabilityNode = CurNISTXML.SelectSingleNode("/table[1]/tbody/tr[1]");  //*[@id="mtconnect content"]/table[1]/tbody/tr[1]/td[7] // Xpath Availability
        var CurNISTStatus = AvailabilityNode.InnerText; //      //*[@id="mtconnect content"]/ul/li[1]


        string CurNistX = ""; //      //*[@id="mtconnect content"]/table[5]/tbody/tr/td[7]
        string CurNistY = ""; //      //*[@id="mtconnect content"]/table[6]/tbody/tr/td[7]

        Console.WriteLine("-------BEGIN NIST DATA PACKET-------");
        Console.WriteLine("NIST Time  : " + creationTime.InnerText);
        Console.WriteLine("NIST Status: " + CurNISTStatus);    
        Console.WriteLine("NIST X Pos.: " + CurNistX);
        Console.WriteLine("NIST Y Pos.: " + CurNistY);
        Console.WriteLine("--------END NIST DATA PACKET--------");

        //var currentNIST = new NISTDataSet()// Create new instance ofNISTdata object
    }

有什么想法吗?

【问题讨论】:

  • 您正在尝试使用 xml 解析 html 网页。您使用了错误的 URL。数据以 XML 形式提供,但您需要使用不同的 URL。请参阅:nist.gov/programs-projects/materials-data-curation-system
  • 你确定吗?如果我将 XML 文档打印到控制台,它就在那里,并且创建时间工作得很好。
  • 这是我第一次写 c#,所以我被一些可能很简单的东西卡住了
  • 您使用的是什么 xml 链接?你发布的只是html。
  • 时间戳只能使用方法第一行给出的链接获取

标签: c# xml xpath


【解决方案1】:

XPath 表达式

/table[1]/tbody/tr[1]

仅当文档的最外层元素是table 元素时才会成功,这似乎不太可能。我没有试图理解页面或代码的逻辑,但这看起来肯定是错误的。路径表达式开头的“/”从树的根中选择。

【讨论】:

  • 是的,尽管如此,我已经尝试了几种不同的方法,这就是为什么我认为单斜线存在
  • @GigaJoules '//table[1]/tbody/tr[1]' 选择你想要的吗?我不清楚您要选择哪个元素。
  • @GigaJoules 我们看到很多问题,人们在他们的 XPath 表达式周围散布随机标点符号,希望它可以充当魔法仙尘。这很少是一种有效的策略。节省自己的时间,阅读手册。
  • 我希望从第一个表格的右上角单元格中提取“可用”一词,以及“线性 x”和“线性 y”表格的“值”数
  • 最终选择属性 ID 是一个更好的选择,因为每个元素都有一个唯一的标识符并且只出现一次。
【解决方案2】:

所以事实证明,我提取 XML 的方式没有任何问题,只有我的路径。

public static void PollNIST()
        {
            string NISTSourceURL = "https://smstestbed.nist.gov/vds/current";  // Gives us a human friendly reference to the HTMl
            // string NistXmlUrl = // Someone on stackexchange is claiming that there is another url for the XML but viewsource says otherwise 
            //-------------------------------- Current (mostly) Working Version---------------------------------------------------------------------------------
            var NISTHttpClient = new HttpClient();
            var NISTXMLRaw = NISTHttpClient.GetStringAsync(NISTSourceURL);  // We now have all of the HTML / XML Data as a raw string
                                                                            //Console.WriteLine(MazXMLRaw.Result);                   // Prints the resulting HTML to a terminal as a debug tool    (Works)   
            XmlDocument CurNISTXML = new XmlDocument();               // Generate Blank XML Doc
            CurNISTXML.LoadXml(NISTXMLRaw.Result);                     // This (".result") passes the actual string?, should then be loaded into new XML file

            // Get CreationTime (WORKING!)
            XmlNodeList elementHeader = CurNISTXML.GetElementsByTagName("Header");
            XmlNode curNISTHeader = elementHeader.Item(0);
            XmlAttribute creationTime = curNISTHeader.Attributes[0];  // We now have the creationTime element          
            string CurNISTTime = creationTime.InnerText;  //      //*[@id="mtconnect content"]/ul/li[1]

            // Get availability (WORKING!)
            XmlNodeList nodeAvailability = CurNISTXML.GetElementsByTagName("Availability");
            XmlNode availability = nodeAvailability.Item(0); // I think this is maybe a bit of a hackish / improper way to do this?
            string curNISTStatus = availability.InnerText;

            //Get linear tool X Coord.
            XmlNodeList deviceStream = CurNISTXML.GetElementsByTagName("ComponentStream");
            XmlNode linearCompXStream = deviceStream.Item(4);
            string curNISTX = linearCompXStream.InnerText; //  We do not need to break down the nodes any further as the value is the only text within

            //Get Linear tool y Coord.            
            XmlNode linearCompYStream = deviceStream.Item(5);
            string curNISTY = linearCompYStream.InnerText; //  We do not need to break down the nodes any further as the value is the only text within


            Console.WriteLine("-------BEGIN NIST DATA PACKET-------");
            Console.WriteLine("NIST Time  : " + creationTime.InnerText);
            Console.WriteLine("NIST Status: " + curNISTStatus);    
            Console.WriteLine("NIST X Pos.: " + curNISTX);
            Console.WriteLine("NIST Y Pos.: " + curNISTY);
            Console.WriteLine("--------END NIST DATA PACKET--------");

            //var currentNIST = new NISTDataSet()// Create new instance ofNISTdata object
        }

效果很好。

【讨论】:

    猜你喜欢
    • 2012-09-10
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 2011-04-24
    • 2011-03-11
    相关资源
    最近更新 更多