Как получить текст элемента внутри разметки CDATA через XPath?
Рассмотрим следующий фрагмент xml:
<Obj>
<Name><![CDATA[SomeText]]></Name>
</Obj>
Как получить значение "SomeText" через XPath? Я использую Nauman Leghari (отлично) инструмент Visual XPath.
/Obj/Name
возвращает элемент
/Obj/Name/text()
возвращает пустой
Я не думаю, что это проблема с инструментом (я могу ошибаться) - я также читаю, что XPath не может извлечь CDATA (см. последний ответ в эта нить) - это звучит странно для меня.
Ответы
Ответ 1
Я думаю, что поток, на который вы ссылаетесь, говорит о том, что сама разметка CDATA игнорируется XPATH, а не текст, содержащийся в разметке CDATA.
Я предполагаю, что проблема с инструментом, исходный код доступен для скачивания, возможно, вы можете его отладить...
Ответ 2
/Obj/Name/text()
- это XPath для возврата содержимого разметки CDATA.
Что меня отбросило, так это поведение свойства Value. Для XMLNode (мир DOM) свойство XmlNode.Value элемента (с CDATA или иначе) возвращает Null. Свойство InnerText предоставит вам содержимое CDATA/Text.
Если вы используете Xml.Linq, XElement.Value возвращает содержимое CDATA.
string sXml = @"
<object>
<name><![CDATA[SomeText]]></name>
<name>OtherName</name>
</object>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml( sXml );
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable);
Console.WriteLine(@"XPath = /object/name" );
WriteNodesToConsole(xmlDoc.SelectNodes("/object/name", nsMgr));
Console.WriteLine(@"XPath = /object/name/text()" );
WriteNodesToConsole( xmlDoc.SelectNodes("/object/name/text()", nsMgr) );
Console.WriteLine(@"Xml.Linq = obRoot.Elements(""name"")");
XElement obRoot = XElement.Parse( sXml );
WriteNodesToConsole( obRoot.Elements("name") );
Вывод:
XPath = /object/name
NodeType = Element
Value = <null>
OuterXml = <name><![CDATA[SomeText]]></name>
InnerXml = <![CDATA[SomeText]]>
InnerText = SomeText
NodeType = Element
Value = <null>
OuterXml = <name>OtherName</name>
InnerXml = OtherName
InnerText = OtherName
XPath = /object/name/text()
NodeType = CDATA
Value = SomeText
OuterXml = <![CDATA[SomeText]]>
InnerXml =
InnerText = SomeText
NodeType = Text
Value = OtherName
OuterXml = OtherName
InnerXml =
InnerText = OtherName
Xml.Linq = obRoot.Elements("name")
Value = SomeText
Value = OtherName
Оказалось, что у автора Visual XPath был TODO для типа XmlNodes CDATA. Немного фрагмента кода, и теперь у меня есть поддержка CDATA.
![alt text]()
MainForm.cs
private void Xml2Tree( TreeNode tNode, XmlNode xNode)
{
...
case XmlNodeType.CDATA:
//MessageBox.Show("TODO: XmlNodeType.CDATA");
// Gishu
TreeNode cdataNode = new TreeNode("![CDATA[" + xNode.Value + "]]");
cdataNode.ForeColor = Color.Blue;
cdataNode.NodeFont = new Font("Tahoma", 12);
tNode.Nodes.Add(cdataNode);
//Gishu
break;
Ответ 3
Разделы CDATA - это лишь часть того, что в XPath известно как text node
или XML Infoset в качестве "фрагментов элементов информации о символах".
Очевидно, что ваш инструмент ошибочен. Другие инструменты, поскольку XPath Visualizer правильно выделяют текст элемента Name
при оценке этого выражения XPath:
/*/Name/text()
Можно также написать простое преобразование XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
"<xsl:value-of select="/*/Name"/>"
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к предоставленному XML-документу:
<Obj>
<Name><![CDATA[SomeText]]></Name>
</Obj>
получается правильный результат:
"SomeText"
Ответ 4
Посмотрите, поможет ли это - http://www.zrinity.com/xml/xpath/
XPATH =/Obj/Название/текст()
Ответ 5
Предполагалось, что будет другое поле хэша md5 из cdata. Затем вы можете использовать xpath для запроса на основе md5 без проблем
<sites>
<site>
<name>Google</name>
<url><![CDATA[http://www.google.com]]></url>
<urlMD5>ed646a3334ca891fd3467db131372140</urlMD5>
</site>
</sites>
Затем вы можете выполнить поиск:
/sites/site[urlMD5=ed646a3334ca891fd3467db131372140]