Как получить текст элемента внутри разметки CDATA через XPath? - PullRequest
29 голосов
/ 20 февраля 2009

Рассмотрим следующий фрагмент XML:

<Obj>
   <Name><![CDATA[SomeText]]></Name>
</Obj>

Как мне получить значение SomeText через XPath? Я использую инструмент Наумана Легари (отлично) Visual XPath .
/Obj/Name возвращает элемент
/Obj/Name/text() возвращает пустое значение

Я не думаю, что это проблема с инструментом (я могу ошибаться) - я также читал, что XPath не может извлечь CDATA (см. Последний ответ в этой теме ) - что звучит немного странно я.

Ответы [ 5 ]

20 голосов
/ 20 февраля 2009

/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 для CDATA-типа XmlNodes. Небольшой фрагмент кода, и теперь у меня есть поддержка 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;
10 голосов
/ 20 февраля 2009

Разделы CDATA - это только часть того, что в XPath известно как text node или в XML Infoset как «порции символа». информационные элементы ".

Очевидно, ваш инструмент неверен . Другие инструменты, такие как Визуализатор XPath , правильно выделяют текст элемента 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"
8 голосов
/ 20 февраля 2009

Я думаю, что поток, на который вы ссылались, говорит, что сама разметка CDATA игнорируется XPATH, а не текст, содержащийся в разметке CDATA.

Я предполагаю, что проблема в инструменте, исходный код доступен для загрузки, возможно, вы можете отладить его ...

3 голосов
/ 20 февраля 2009

Посмотрите, поможет ли это - http://www.zrinity.com/xml/xpath/
XPATH = / Obj / Имя / текст ()

0 голосов
/ 26 мая 2010

Было бы предложено иметь другое поле хеша 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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...