Получить нод XML по его названию

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns:yt="http://youtube.com/yt/2012/10/10" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" minBufferTime="PT1.500S" profiles="urn:mpeg:dash:profile:isoff-main:2011" type="static" mediaPresentationDuration="PT26246.117S">
	<Period>
         ...
</Period>
</MPD>

        private void ParseDashManifest(string dashManifestString)
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(dashManifestString);
            XmlNode period = xml.DocumentElement.SelectSingleNode("Period"); //null
            foreach (XmlNode node in period)
            {
                System.Diagnostics.Debug.WriteLine(node.Name);
            }
        }

Как найти нод Period без прохода циклом? Должен же быть стандартный метод для этого. Даже в Delphi он есть.

Должно работать, наверно что-то с XML.

using System;
using System.Xml;

public class Program
{
	public static void Main()
	{
		XmlDocument xml = new XmlDocument();
		xml.LoadXml(@"<?xml version=""1.0"" encoding=""UTF-8""?>
<MPD>
	<Period> <Child /> </Period>
</MPD>");
		XmlNode period = xml.DocumentElement.SelectSingleNode("Period");
		foreach (XmlNode child in period)
		{
			Console.WriteLine(child.Name);
		}
	}
}

https://dotnetfiddle.net/38Q8hY

А, тут же неймспейс.

Надо либо как-то с помощью XmlNamespaceManager Class (System.Xml) | Microsoft Docs (передать в SelectSingleNode вторым параметром), либо так

using System;
using System.Xml;

public class Program
{
	public static void Main()
	{
		XmlDocument xml = new XmlDocument();
		xml.LoadXml(@"<?xml version=""1.0"" encoding=""UTF-8""?>
<MPD xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns=""urn:mpeg:DASH:schema:MPD:2011"" xmlns:yt=""http://youtube.com/yt/2012/10/10"" xsi:schemaLocation=""urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd"">
	<Period> <Child /> </Period>
</MPD>");
		XmlNode period = xml.DocumentElement.SelectSingleNode("//*[local-name()='Period']");
		foreach (XmlNode child in period)
		{
			Console.WriteLine(child.Name);
		}
	}
}

Ну или как-нибудь удалить атрибут xmlns.

Не может быть. На Delphi работает.

Видимо библиотека в Дельфи не поддерживает неймспейсы.

всмысле?

Получить нод XML по его названию - #3 от пользователя AlexP

Я знаю, что есть ноды и аттрибуты. А неймспейс (namespace) это что? Из википедии нифига не понял.
Почему и как эти неймспейсы мешают поиску нода?

каким образом он на что-то влияет? Ничего же не меняется.

и почему с такой фигнёй ("//*[local-name()='Period']") работает?

XML Namespaces

Тут ко всем элементам внутри добавится неймспейс, так что его полное имя больше не Period.

Через XmlNamespaceManager можно объявить неймспейсы для XPath и использовать их в запросе.

https://stackoverflow.com/a/40796315/964478

            var nsmgr = new XmlNamespaceManager(xml.NameTable);
            nsmgr.AddNamespace("u", "urn:mpeg:DASH:schema:MPD:2011");
            XmlNode period = xml.DocumentElement.SelectSingleNode("u:Period", nsmgr);

local-name() возвращает имя без неймспейса.

https://developer.mozilla.org/en-US/docs/Web/XPath/Functions/local-name

Боюсь даже спрашивать, кто и зачем придумывает такие удобства…
В JSON’ах же таких удобств нет :thinking:

По первой ссылке был же пример зачем. Как и любые неймспейсы, для решения конфликтов имен.

JSON проще, но там есть другие проблемы, например, с тем, что есть куча разных спецификаций и парсеров конфликтующих друг с другом. Забавные факты о языках программирования/библиотеках/технологиях - #14 от пользователя AlexP

И в некотором он уж слишком сильно ограничен, нельзя даже добавить коммент/закомментить строку, что бывает полезно в конфигах и т.п.

что-то вообще странное происходит :scream: :dizzy_face: :ghost:
я читаю отсюда


а получаю отсюда

Так а в коде что?


        private void ParseDashManifest(string dashManifestString)
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(dashManifestString);
            XmlNode period = xml.DocumentElement.SelectSingleNode("//*[local-name()='Period']");
            foreach (XmlNode nodeAdaptationSet in period)
            {

                string mimeType = nodeAdaptationSet.Attributes["mimeType"].Value;
                string[] mimeTypeSplit = mimeType.Split('/');
                if (mimeType.Contains("video"))
                {
                    foreach (XmlNode node in nodeAdaptationSet)
                    {
                        if (node.Name.Equals("Representation"))
                        {
                            YouTubeVideoFile videoFile = new YouTubeVideoFile();
                            videoFile.dashManifestUrls = new List<string>();
                            //здесь 133, всё прекрасно, птички поют
                            videoFile.formatId = int.Parse(node.Attributes["id"].Value);
                            videoFile.width = int.Parse(node.Attributes["width"].Value);
                            videoFile.height = int.Parse(node.Attributes["height"].Value);
                            videoFile.bitrate = int.Parse(node.Attributes["bandwidth"].Value);
                            videoFile.fps = int.Parse(node.Attributes["frameRate"].Value);
                            videoFile.mimeCodecs = node.Attributes["codecs"].Value;
                            videoFile.mimeType = mimeType + "; codecs=\"" + videoFile.mimeCodecs + "\"";
                            videoFile.mimeExt = mimeTypeSplit[1];
                            videoFile.fileExtension = videoFile.mimeExt == "mp4" ? "m4v" : videoFile.mimeExt;
                            videoFile.isDashManifest = true;
                            videoFile.dashManifestUrls = new List<string>();

                            //а здесь получается ссылка на файл с ID 139
                            XmlNode nodeBaseUrl = node.SelectSingleNode("//*[local-name()='BaseURL']");
                            string baseUrl = nodeBaseUrl.InnerText;
                            //дальнейшее уже бессмысленно
                            XmlNode nodeSegmentList = node.SelectSingleNode("//*[local-name()='SegmentList']");
                            XmlNode nodeInitialization = nodeSegmentList.SelectSingleNode("//*[local-name()='Initialization']");
                            if (nodeInitialization != null)
                            {
                                string sourceUrl = nodeInitialization.Attributes["sourceURL"].Value; //тут range/0-640
                                videoFile.dashManifestUrls.Add(baseUrl + sourceUrl);
                            }
                            foreach (XmlNode nodeSegment in nodeSegmentList)
                            {
                                if (nodeSegment.Name.Equals("SegmentURL"))
                                {
                                    string segmentUrl = baseUrl + nodeSegment.Attributes["media"].Value;
                                    videoFile.dashManifestUrls.Add(segmentUrl);
                                }
                            }

                            videoFiles.Add(videoFile);
                        }
                    }
                }
                else
                if (mimeType.Contains("audio"))
                {

                }
            }
        }

По-моему // всегда с корня документа начинает, надо . добавить, чтобы искать от текущего.
И чтобы искать среди прямых потомков (один уровень) можно использовать /.

node.SelectSingleNode("./*[local-name()='BaseURL']")