DOBON.NET DOBON.NETプログラミング掲示板過去ログ

XMLパーサーの大文字小文字解析について

環境/言語:[XP,net]
分類:[.NET]


<aaa>
<bbb value='AbcD'></bbb>
<bbb value='aBCd'></bbb>
</aaa>

↑のようにaaa/bbbのinnerTextにabcdと設定されているのですが、
XPathでは、大文字・小文字を判定してしまうため、
aaa/bbb[@value='AbcD']と明確に指定しなければ、ノードを取得できません。

aaa/bbb[@value='aBCd']と検索の方も大文字・小文字が入り乱れ、
検索される方のXMLも大文字・小文字が入り乱れた中で、
2ノードを取得する方法は存在するのでしょうか?

よろしくお願い致します。
■No24614に返信(RUNNEさんの記事)
> 検索される方のXMLも大文字・小文字が入り乱れた中で、
> 2ノードを取得する方法は存在するのでしょうか?

2008 で良いのかな?

Imports System
Module Test
  Sub Main()
    'Dim doc = <aaa><bbb value='AbcD'></bbb><bbb value='aBCd'></bbb><bbb value='test'/></aaa>
    'Dim nodes = From n In doc.<bbb> Where UCase(n.@value) = "ABCD"

    Dim doc As XDocument = XDocument.Parse("<aaa><bbb value='AbcD'></bbb><bbb value='aBCd'></bbb></aaa>")
    Dim nodes = From n In doc.<aaa>.<bbb> Where UCase(n.@value) = "ABCD"

    For Each n In nodes
      Console.WriteLine( n )
    Next
  End Sub
End Module
■No24616に追記(魔界の仮面弁士の記事)
>>検索される方のXMLも大文字・小文字が入り乱れた中で、
>>2ノードを取得する方法は存在するのでしょうか?
> 2008 で良いのかな?

.NET 3.5 未満の環境でも動作するよう、XLinq を使わない記法にしてみました。
XPath 関数の「translate」で大文字化しています。
(MSXML なら、ms:string-compare 関数が使えるのだけれども…)
http://msdn.microsoft.com/ja-jp/library/ms256138.aspx

Imports System
Imports System.Text
Imports System.Xml
Imports Microsoft.VisualBasic
Module Test
  Sub Main()
    Dim sb As New StringBuilder()
    For c As Integer = AscW("a"c) To AscW("z"c)
        sb.Append(ChrW(c))
    Next

    Dim doc As New XmlDocument()
    doc.LoadXml("<aaa><bbb value='AbcD'></bbb><bbb value='aBCd'></bbb></aaa>")

    Dim XPath As String = String.Format("/aaa/bbb[translate(@value, '{1}', '{2}') = '{0}']", _
        "ABCD", sb.ToString(), UCase(sb.ToString()))

    For Each node As XmlElement In doc.SelectNodes(XPath)
        Console.WriteLine(node.OuterXml)
    Next
  End Sub
End Module


あるいは XPath だけに頼るのではなく、
  For Each attr As XmlAttribute In doc.SelectNodes("/aaa/bbb/@value")
    If UCase(attr.Value) = "ABCD" Then
      Dim node As XmlNode = attr.OwnerElement
      Console.WriteLine(node.OuterXml)
    End If
  Next
のように、VB コードと併用するとか。
■No24618にさらに追記(魔界の仮面弁士の記事)
> ■No24616に追記(魔界の仮面弁士の記事)
> (MSXML なら、ms:string-compare 関数が使えるのだけれども…)
> http://msdn.microsoft.com/ja-jp/library/ms256138.aspx

System.Data.SqlXml.dll に、ms:string-compare 関数の実装として、
 System.Xml.Xsl.Runtime.XsltFunctions.MSStringCompare メソッド
がありました。この関数を用いる事で、大文字小文字を区別しない比較の為に
 /aaa/bbb[ms:string-compare(@value, 'ABCD', 'ja-JP', 'i') = 0]
といった XPath 式を利用できる事を確認できました。
 第1引数: 比較文字列1
 第2引数: 比較文字列2
 第3引数: 言語指定、省略時は現在のスレッドの言語
 第4引数: u(vbBinaryCompareに相当)もしくはi(vbTextCompareに相当)、省略時はu
 戻り値: 負数(-1)/ゼロ(0)/正数(1)のいずれかの数値、意味はVB の StrComp 関数と同様
http://msdn.microsoft.com/ja-jp/library/ms256114.aspx


ただし、XPath 式から追加の関数を利用するためには、
面倒なことに XsltContext.ResolveFunction メソッド等を
オーバーライドしたクラスを用意する必要があるようです。
http://www.tkachenko.com/blog/archives/000649.html
多くのご回答をありがとうございます。
ちょっと、自分には、勉強不足の箇所もあり、一番簡単にな以下の方法にて
実装させて頂きました。

ありがとうございました。

>あるいは XPath だけに頼るのではなく、
> For Each attr As XmlAttribute In doc.SelectNodes("/aaa/bbb/@value")
> If UCase(attr.Value) = "ABCD" Then
> Dim node As XmlNode = attr.OwnerElement
> Console.WriteLine(node.OuterXml)
> End If
> Next
>のように、VB コードと併用するとか。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板