Как запросить пространство имен по умолчанию с помощью MSXML
У меня есть немного XML:
<?xml version="1.0" ?>
<Project ToolsVersion="4.0">
<PropertyGroup Condition="'$(key)'=='1111'">
<Key>Value</Key>
</PropertyGroup>
</Project>
Примечание: это не фактический XML, который я использую, он просто красивее и короче и демонстрирует проблему.
Используя MSXML, я могу запрашивать узлы:
IXMLDOMNode node = doc.selectSingleNode("//PropertyGroup/@Condition");
И это прекрасно работает
Condition="'$(ключ)'=='1111'"
Но это не совсем тот XML, который у меня есть
На самом деле XML, который я имею, содержит объявление пространства имен:
XMLNS ="http://schemas.microsoft.com/developer/msbuild/2003"
сделать настоящий документ XML:
<?xml version="1.0" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(key)'=='1111'">
<Key>Value</Key>
</PropertyGroup>
</Project>
Теперь мой запрос:
IDOMNode node = doc.selectSingleNode("//PropertyGroup/@Condition");
не возвращает подходящих узлов.
Как я могу запросить пространство имен по умолчанию, используя MSXML?
Примечание:
я уже знаю, как запросить пространство имен не по умолчанию в XML; ты используешь:
doc.setProperty("SelectionNamespaces", "xmlns="http://schemas.microsoft.com/developer/msbuild/2003");
я уже знаю, как запросить пространство имен по умолчанию в.NET. Вы используете диспетчер пространства имен, присваиваете пространству имен по умолчанию имя, затем запрашиваете это имя, а затем можете запросить пространство имен не по умолчанию, поскольку оно больше не по умолчанию
я могу просто удалить наступление
xmlns
текст из XML-строки, которую я получаю, но я бы предпочел "сделать это правильно"
Как запросить пространство имен по умолчанию или без имени с использованием MSXML?
Примечание. На самом деле в XML я использую вывод SQL Server XML ShowPlan:
<?xml version="1.0" encoding="UTF-16" standalone="yes"?>
<ShowPlanXML Version="1.1" Build="10.50.1600.1"
xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
<BatchSequence>
<Batch>
...
</Batch>
</BatchSequence>
</ShowPlanXML>
Снова вы можете увидеть оскорбительную декларацию пространства имен. Удаление работает, но это утомительно.
Что еще ты пробовал?
я также попытался установить SelectionNamespace:
doc.setProperty('SelectionNamespaces',
'xmlns="http://schemas.microsoft.com/developer/msbuild/2003"');
как Microsoft намекает на в статье KB.
Как мне получить пространство имен по умолчанию?
На самом деле меня не волнуют пространства имен. Мой запрос имеет смысл, и я хочу, чтобы он работал. Итак, еще один подход к вопросу может быть:
Как я могу запросить пространство имен по умолчанию, или нет, и неважно, что это имя пространства имен (или нет)?
Примечание: msxml является нативным кодом и использует его из нативного компилятора Win32 (т.е. без.NET Framework или CLR)
2 ответа
Явно дайте пространству имен имя, когда вы добавите его в SelectionNamespaces
:
doc.setProperty("SelectionNamespaces",
"xmlns:peanut='http://schemas.microsoft.com/developer/msbuild/2003'");
а затем выполнить запрос, используя это пространство имен:
IDOMNode node = doc.selectSingleNode("//peanut:PropertyGroup/@Condition");
Вы можете дать этому пространству имен любое сокращенное имя, которое хотите (peanut
в этом случае). А затем используйте сокращение в качестве префикса (peanut:PropertyGroup
в этом случае).
Предыдущие предложения
Я бы попробовал переехать в Xml.Linq
,
Вот пример (с пространством имен).
try
{
XDocument xDoc1 = XDocument.Parse("<?xml version=\"1.0\" ?><Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\"><PropertyGroup Condition=\"'$(key)'=='1111'\"><Key>Value</Key></PropertyGroup></Project>");
XNamespace ns1 = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");
var list1 = from list in xDoc1.Descendants(ns1 + "Project")
from item in list.Elements(ns1 + "PropertyGroup")
/* where item.Element(ns + "HintPath") != null */
where item.Attribute("Condition") != null
select new
{
MyCondition = item.Attribute("Condition") == null ? "Not Here!" : item.Attribute("Condition").Value,
MyFake = item.Attribute("DoesNotExistTest") == null ? "Not Here Sucker!" : item.Attribute("DoesNotExistTest").Value
};
foreach (var v in list1)
{
Console.WriteLine(v.ToString());
}
XDocument xDoc2 = XDocument.Parse("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?> <ShowPlanXML Version=\"1.1\" Build=\"10.50.1600.1\" xmlns=\"http://schemas.microsoft.com/sqlserver/2004/07/showplan\"> <BatchSequence> <Batch>Something I Threw In Here</Batch> </BatchSequence> </ShowPlanXML> ");
XNamespace ns2 = XNamespace.Get("http://schemas.microsoft.com/sqlserver/2004/07/showplan");
var list2 = from list in xDoc2.Descendants(ns2 + "ShowPlanXML")
from item in list.Elements(ns2 + "BatchSequence")
/* where item.Attribute("Condition") != null */
where item.Element(ns2 + "Batch") != null
select new
{
BatchValue = (item.Element(ns2 + "Batch") == null) ? string.Empty : item.Element(ns2 + "Batch").Value
};
foreach (var v in list2)
{
Console.WriteLine(v.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Если вы похожи на меня и не хотите менять свое.SelectNodes("//Test")
код, соответствующий каждому возможному пространству имен, вы можете обратиться к моему ответу на вопрос « Как игнорировать пространство имен XML».
В основном я использовал метод.transformNodeToObject
так :
Public Sub fixNS(ByRef doc As DOMDocument60)
' Create a new XML document (fixNS0) that contains an XSLT style sheet.
' The XSLT style sheet will remove namespace prefixes from XML elements and attributes.
' The resulting XML document will have the same content as the original, but with the namespace prefixes removed.
Dim fixNS0 As New DOMDocument60
fixNS0.LoadXML ("<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" & _
"<xsl:output method='xml' indent='yes' omit-xml-declaration='yes' />" & _
"<xsl:template match='comment()'> <xsl:copy/> </xsl:template>" & _
"<xsl:template match='*'>" & _
"<xsl:text>
</xsl:text>" & _
"<xsl:element name='{local-name(.)}'> <xsl:apply-templates select='@* | node()'/> </xsl:element>" & _
"<xsl:text>
</xsl:text>" & _
"</xsl:template> <xsl:template match='@*'>" & _
"<xsl:attribute name='{local-name(.)}'> <xsl:value-of select='.'/> </xsl:attribute>" & _
"</xsl:template> </xsl:stylesheet>")
' Apply the XSLT style sheet (in fixNS0) to the XML document (in doc).
' The result of the transformation is written back to the same XML document (in doc).
doc.transformNodeToObject fixNS0, doc
End Sub