2017-08-12 27 views
0

我正在寫一個C#程序來查詢XML文件(書籍數據庫)。
我想用定義的作者查詢所有記錄:<作者>被定義爲<作者>的列表。
到目前爲止,我使用了以下內容:XPath表達式提取記錄與定義的孩子

itemNodes = xmlDoc.SelectNodes("//record[contains(translate(authors/author, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '" + strSearch.ToLower() + "')]"); 

正是有了這種記錄OK:

<record> 
    <_formats>PDF</_formats> 
    <publisher>Alessio Roberti Editore</publisher> 
    <authors sort="Dilts, Robert"> 
    <author>Robert Dilts</author> 
    </authors> 
... 

但卻忽略這一個:

<record> 
    <_formats>AZW3, EPUB</_formats> 
    <publisher>Alessio Roberti Editore</publisher> 
    <authors sort="Gilligan, Stephen &amp; Dilts, Robert"> 
    <author>Stephen Gilligan</author> 
    <author>Robert Dilts</author> 
    </authors> 
... 

這裏筆者是第二個項目的名單。
如何更改表達式以返回兩個記錄?

+0

由於您使用的是C#,因此可以改爲使用Linq2Xml。它可以很容易地用來避免文本中的單引號問題,ignorecase比較等。 –

回答

2

如何更改表達式以返回兩個記錄?

夠簡單。變化:

"//record[contains(authors/author, '" + strSearch.ToLower() + "')]" 

到:

"//record[authors/author[contains(., '" + strSearch.ToLower() + "')]]" 

謂詞可以被嵌套。


話雖這麼說,而不是硬編碼的字母,因此限制,你可以搜索字符,請使用C#,以適應搜索所有字符:

var strSearch = "Search"; 
var xpath = String.Format(
    "//record[authors/author[contains(translate(., '{0}', '{1}'), '{1}')]]", 
    strSearch.ToUpper(), 
    strSearch.ToLower() 
); 

這仍然將打破,如果strSearch包含單引號。一定要事先剝去它們。這給你(包裝的可讀性):

//record[authors/author[contains(
    translate(., 'SEARCH', 'search'), 
    'search' 
)]] 

而不是去除單引號,你可以妥善處理。在XPath中沒有轉義序列,所以你不能簡單地以某種方式逃避它們。

O'Connor只能用XPath中的雙引號字符串表示:"O'Connor",因爲'不能存在於單引號字符串中(反之亦然)。不幸的是,這需要事先了解字符串內容,而您並不知道。

但是,您可以構建一個XPath表達式,評估O'Connor,如下所示:concat('O', "'", 'Connor')。這種表達可以自動從任何輸入來實現,不管它包含多少單引號:

string escapeXPath(string input) { 
    if (input.Contains("'")) 
     return "concat('" + String.Join("', \"'\", '", input.Split('\'')) + "')"; 
    return "'" + input + "'"; 
} 

,所以你可以將它像這樣(有上述W/R/T單細微的差別引號):

var strSearch = "O'Connor"; 
var xpath = String.Format(
    "//record[authors/author[contains(translate(., {0}, {1}), {1})]]", 
    escapeXPath(strSearch.ToUpper()), 
    escapeXPath(strSearch.ToLower()) 
); 

,讓你安全的XPath 1.0表達式(包裝的可讀性):

//record[authors/author[contains(
    translate(., concat('O', "'", 'CONNOR'), concat('o', "'", 'connor')), 
    concat('o', "'", 'connor') 
)]] 

不犧牲ABIL可以搜索單引號(或A-Z範圍以外的字符)。

+0

謝謝,但程序崩潰,說* System.Xml.XPath.XPathException:包含需要2個參數* – SteMMo

+0

是的,我已經注意到自己。答案已更新。 – Tomalak

+0

@SteMMo使用'String.Format()'產生更好的代碼。再次更新。 – Tomalak