2014-11-04 3 views
1

Я пытаюсь извлечь некоторые данные SQL в XML из среды Microsoft Dynamics, в настоящее время я использую LINQ To XML в C# для чтения и записи на мой XML-файлы. Мне нужна часть данных из вида SECURITYSUBROLE. Глядя на структуру этого представления, видно, что есть столбец с именем SECURITYSUBROLE. Мой нормальный метод извлечения дал мне этот XML.Как использовать LINQ to XML, когда родительский и дочерний узлы XML имеют одинаковое имя

<SECURITYSUBROLE> 
    <SECURITYROLE>886301</SECURITYROLE> 
    <SECURITYSUBROLE>886317</SECURITYSUBROLE> 
    <VALIDFROM>1900-01-01T00:00:00-06:00</VALIDFROM> 
    <VALIDFROMTZID>0</VALIDFROMTZID> 
    <VALIDTO>1900-01-01T00:00:00-06:00</VALIDTO> 
    <VALIDTOTZID>0</VALIDTOTZID> 
    <RECVERSION>1</RECVERSION> 
    <RECID>886317</RECID> 
</SECURITYSUBROLE> 

Когда я пытаюсь импортировать эти данные позже, я получаю сообщение об ошибке, поскольку родительский узел XML имеет такое же имя, как дочерний узел. Вот фрагмент метода импорта:

XmlReaderSettings settings = new XmlReaderSettings(); 
settings.CheckCharacters = false; 

XmlReader reader = XmlReader.Create(path, settings); 

reader.MoveToContent(); 
int count = 1; 
List<XElement> xmlSubset = new List<XElement>(); 
while (reader.ReadToFollowing(xmlTag)) 
{ 
    if (count % 1000 == 0) 
    { 
    xmlSubset.Add(XElement.Load(reader.ReadSubtree())); 
    XDocument xmlTemp = new XDocument(new XElement(xmlTag)); 
    foreach (XElement elem in xmlSubset) 
    { 
    xmlTemp.Root.Add(elem); 
    } 
    xmlSubset = new List<XElement>(); 
    ImportTableByName(connectionString, tableName, xmlTemp); 
    count = 1; 
    } 
    else 
    { 
    xmlSubset.Add(XElement.Load(reader.ReadSubtree())); 
    count++; 
    } 
    } 
} 

Это в настоящее время неудачи на XmlReader.ReadToFollowing, где он не знает, куда идти дальше из-за имени путаницы. Поэтому мой вопрос состоит из двух частей:

1) Есть ли лучший способ извлечь эти данные, кроме XML?

2) Есть ли способ LINQ To XML, который я могу каким-то образом различать родительский и дочерний узлы, названные точно такими же?

+0

Позвольте мне угадать, вы используете 'метод Descendants'? Вместо этого используйте «Элементы», и все должно быть в порядке. – MarcinJuraszek

ответ

1

Чтобы получить элементы (в вашем случае) для SECURITYSUBROLE вы можете проверить, чтобы увидеть, если есть дети элемента:

XElement root = XElement.Load(path); 
var subroles = root.Descendants("SECURITYSUBROLE") // all subroles 
        .Where(x => !x.HasElements); // only subroles without children 
+0

Это было бы идеальным решением, если бы я имел дело с файлами XML нормального размера, причиной, по которой я использовал XmlReader, было то, что генерируемые файлы XML иногда имеют размер до 2 ГБ или более и будут удалены из-за исключения из памяти, если я попытаюсь загрузите всю вещь в объект XElement. Есть ли способ по-прежнему использовать ваше решение при использовании XmlReader? –

+0

@crypticApps Заголовок вашего вопроса говорит Linq-to-xml, то есть не XmlReader. Почему бы вам не сделать свой проект 64-битным и разместить в разных флагах компиляции, которые позволят вам использовать много памяти. Если вы хотите знать, как это сделать, спросите об этом как отдельный вопрос. –

+0

Я принимаю этот ответ, потому что это правильно для того, что я спросил, спасибо Чак! –

0

Я собираюсь предложить другой подход:

1) VS2013 (возможно более ранние версии тоже) есть функция для создания класса из источника XML. Получите один из ваших XML-файлов и скопируйте содержимое в буфер обмена. Затем в новом файле класс Edit ->Paste Special ->Paste XML as Classes

2) Посмотрите в XmlSerialization, которая позволит вам преобразовать файл XML в в объекте памяти с сильно типизированным классом.

 XmlSerializer s = new XmlSerializer(yourNewClassTYPE); 
     TextReader r = new StreamReader(XmlFileLocation); 
     var dataFromYourXmlAsAStronglyTypedClass = (yourNewlyClassTYPE) s.Deserialize(r); 
     r.Close();