web-dev-qa-db-ja.com

XPath経由でCDATAマークアップ内の要素テキストを取得するにはどうすればよいですか?

次のxmlフラグメントを検討してください。

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

XPath経由で「SomeText」値を取得するにはどうすればよいですか? Nauman Leghariの(優秀な) Visual XPathツール を使用しています。
_/Obj/Name_は要素を返します
/Obj/Name/text()は空白を返します

ツールに問題があるとは思いません(間違っているかもしれません)-XPathがCDATAを抽出できないことも読んでいます(最後の応答 このスレッドで を参照)-ちょっと奇妙に聞こえます。

30
Gishu

あなたが参照したスレッドは、CDATAマークアップに含まれるテキストではなく、CDATAマークアップ自体がXPATHによって無視されると言っていると思います。

私の推測では、ツールの問題であり、ソースコードはダウンロード可能です。おそらくデバッグできます...

9
Jason

/Obj/Name/text()は、CDATAマークアップのコンテンツを返すXPathです。

私を驚かせたのは、Valueプロパティの動作です。 XMLNode(DOMワールド)の場合、Elementの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の作成者は、XmlNodesのCDATAタイプのTODOを持っていることが判明しました。少しのコードスニペットと私は今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;
22
Gishu

CDATAセクションは、 XPathtext node またはin the XML Infoset as "chunks of character information items"。

明らかに、あなたのツールは間違っていますXPath Visualizer などの他のツールは、このXPath式を評価するときにName要素のテキストを正しく強調表示します:

/*/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"
10

これが役立つかどうかを確認します- http://www.zrinity.com/xml/xpath/
XPATH =/Obj/Name/text()

3
shahkalpesh