Подтвердить что ты не робот

Как получить текст элемента внутри разметки CDATA через XPath?

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

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

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

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

4b9b3361

Ответ 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"

Ответ 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]