Я могу использовать предопределенные пространства имен при загрузке XDocument?

def doit(str)
  r = /\A#{"(#\\d)\\s*"*str.count('#')}\z/      
  str.match(r)&.captures
end

doit "#1#2 #3 "    #=> ["#1", "#2", "#3"]
doit " #1#2 #3 "   #=> nil

Обратите внимание, что регулярные выражения зависят только от количества экземпляров символа '#' в строке. Поскольку в обоих примерах это число равно трем, соответствующие регулярные выражения равны, а именно:

/\A(#\d)\s*(#\d)\s*(#\d)\s*\z/

Это регулярное выражение было построено следующим образом.

str = "#1#2 #3 "
n = str.count('#')
  #=> 3
s = "(#\\d)\\s*"*n
  #=> "(#\\d)\\s*(#\\d)\\s*(#\\d)\\s*" 
/\A#{s}\z/ 
  #=> /\A(#\d)\s*(#\d)\s*(#\d)\s*\z/ 

Регулярное выражение гласит: «соответствует началу строки, за которым следуют три идентичные группы захвата, за каждой из которых необязательно следуют пробелы, за которыми следует конец строки. Поэтому регулярное выражение проверяет правильность строки» и извлекает нужные совпадения из групп захвата.

Оператор безопасной навигации , & необходим в случае отсутствия совпадения (match возвращает nil).

Комментарий ОП относится к обобщению вопроса, в котором символ фунта ('#') является необязательным. Это можно решить, изменив регулярное выражение следующим образом.

def doit(str)
  r = /\A#{"(?:#?(\\d)(?=#|\\s+|\\z)\\s*)"*str.count('0123456789')}\z/
  str.match(r)&.captures
end

doit "1 2 #3 "     #=> ["1", "2", "3"] 
doit "1 2 #3 "     #=> ["1", "2", "3"] 
doit "1#2"         #=> ["1", "2"] 
doit " #1 2 #3 "   #=> nil   
doit "#1 2# 3 "    #=> nil 
doit " #1 23 #3 "  #=> nil 

Для строк, содержащих три цифры, регулярное выражение имеет вид:

/\A(?:#?(\d)(?=#|\s+|\z)\s*)(?:#?(\d)(?=#|\s+|\z)\s*)(?:#?(\d)(?=#|\s+|\z)\s*)\z/ 

[1120]

Хотя это верно что это регулярное выражение потенциально может быть довольно длинным, это не обязательно означает, что оно будет относительно неэффективным, так как предугадывание довольно локализовано.

5
задан James Sulak 18 May 2009 в 20:42
поделиться

2 ответа

Вы можете создать XmlReader с XmlParserContext , который знает о пространствах имен; следующие действия работают для XmlDocument и XDocument :

class SimpleNameTable : XmlNameTable {
    List<string> cache = new List<string>();
    public override string Add(string array) {
        string found = cache.Find(s => s == array);
        if (found != null) return found;
        cache.Add(array);
        return array;
    }
    public override string Add(char[] array, int offset, int length) {
        return Add(new string(array, offset, length));
    }
    public override string Get(string array) {
        return cache.Find(s => s == array);
    }
    public override string Get(char[] array, int offset, int length) {
        return Get(new string(array, offset, length));
    }
}
static void Main() {
    XmlNamespaceManager mgr = new XmlNamespaceManager(new SimpleNameTable());
    mgr.AddNamespace("a", "http://foo/bar");
    XmlParserContext ctx = new XmlParserContext(null, mgr, null,
        XmlSpace.Default);
    using (XmlReader reader = XmlReader.Create(
        new StringReader(@"<root><a:element/></root>"), null, ctx)) {

        XDocument doc = XDocument.Load(reader);

        //XmlDocument doc = new XmlDocument();
        //doc.Load(reader);
    }
}
5
ответ дан 14 December 2019 в 08:59
поделиться

Основываясь на предыдущем ответе, вы можете сохранить префиксы пространства имен, сначала загрузив его в XmlDocument и проанализировав OuterXml XmlDocument в XDocument

XDocument LoadWithPrefix(Stream stream)
{
    XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
    mgr.AddNamespace("a", "http://foo/bar");
    XmlParserContext ctx = new XmlParserContext(null, mgr, null, XmlSpace.Default);
    using (XmlReader reader = XmlReader.Create(stream, null, ctx)) 
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(reader);
        return XDocument.Parse(doc.OuterXml);
    }
}
2
ответ дан 14 December 2019 в 08:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: