C # 코드에서 (큰) XML을 구문 분석하는 가장 좋은 방법은 무엇입니까?
서버에서 GML 기반 XML 스키마 (아래 샘플)의 "기능"을 검색하기 위해 C #으로 GIS 클라이언트 도구를 작성하고 있습니다. 추출은 100,000 개의 기능으로 제한됩니다.
나는 가장 큰 extract.xml 이 약 150MB까지 올라갈 수 있다고 생각하므로, 분명히 DOM 파서가 나왔다. XmlSerializer 와 XSD.EXE 생성 바인딩-또는 -XmlReader 와 손으로 만든 개체 그래프 사이에서 결정하려고 노력 해왔다 .
아니면 아직 고려하지 않은 더 나은 방법이 있습니까? XLINQ 또는 ????
아무도 나를 안내 할 수 있습니까? 특히 주어진 접근 방식의 메모리 효율성과 관련하여. 그렇지 않다면 두 솔루션을 "프로토 타입"하고 나란히 프로파일 링해야합니다.
나는 .NET에서 약간의 원시 새우입니다. 어떤 지침이라도 대단히 감사하겠습니다.
감사합니다. 키스.
샘플 XML- 최대 100,000 개, 기능 당 최대 234,600 개의 좌표.
<feature featId="27168306" fType="vegetation" fTypeId="1129" fClass="vegetation" gType="Polygon" ID="0" cLockNr="51598" metadataId="51599" mdFileId="NRM/TIS/VEGETATION/9543_22_v3" dataScale="25000">
<MultiGeometry>
<geometryMember>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>153.505004,-27.42196 153.505044,-27.422015 153.503992 .... 172 coordinates omitted to save space ... 153.505004,-27.42196</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</geometryMember>
</MultiGeometry>
</feature>
XmlReader
큰 XML 문서를 구문 분석하는 데 사용 합니다. XmlReader
XML 데이터에 대한 빠르고 정방향 전용이며 캐시되지 않은 액세스를 제공합니다. (Forward-only는 XML 파일을 처음부터 끝까지 읽을 수 있지만 파일에서 뒤로 이동할 수 없음을 의미합니다.) XmlReader
적은 양의 메모리를 사용하며 간단한 SAX 판독기를 사용하는 것과 같습니다.
using (XmlReader myReader = XmlReader.Create(@"c:\data\coords.xml"))
{
while (myReader.Read())
{
// Process each node (myReader.Value) here
// ...
}
}
XmlReader를 사용하여 최대 2GB (기가 바이트) 크기의 파일을 처리 할 수 있습니다.
참조 : Visual C #을 사용하여 파일에서 XML을 읽는 방법
2009 년 5 월 14 일 Asat : 하이브리드 접근 방식으로 전환했습니다 ... 아래 코드를 참조하십시오.
이 버전은 두 가지 장점을 모두 가지고 있습니다.
* XmlReader / XmlTextReader (메모리 효율성-> 속도); 및
* XmlSerializer (코드 생성기-> 개발 확장 성 및 유연성).
XmlTextReader를 사용하여 문서를 반복하고 XSD.EXE로 생성 된 XmlSerializer 및 "XML 바인딩"클래스를 사용하여 역 직렬화하는 "doclet"을 만듭니다.
이 레시피는 보편적으로 적용 할 수 있고 빠르다고 생각합니다 ... 56,000 GML 기능이 포함 된 201MB XML 문서를 약 7 초 만에 구문 분석하고 있습니다.이 응용 프로그램의 이전 VB6 구현은 구문 분석하는 데 몇 분 (또는 몇 시간)이 걸렸습니다. 큰 추출물 ... 그래서 나는 잘 어울려 보인다.
다시 한 번 소중한 시간을내어 주신 포럼 사이트에 큰 감사를드립니다. 정말 감사.
모두 건배. 키스.
using System;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Collections.Generic;
using nrw_rime_extract.utils;
using nrw_rime_extract.xml.generated_bindings;
namespace nrw_rime_extract.xml
{
internal interface ExtractXmlReader
{
rimeType read(string xmlFilename);
}
/// <summary>
/// RimeExtractXml provides bindings to the RIME Extract XML as defined by
/// $/Release 2.7/Documentation/Technical/SCHEMA and DTDs/nrw-rime-extract.xsd
/// </summary>
internal class ExtractXmlReader_XmlSerializerImpl : ExtractXmlReader
{
private Log log = Log.getInstance();
public rimeType read(string xmlFilename)
{
log.write(
string.Format(
"DEBUG: ExtractXmlReader_XmlSerializerImpl.read({0})",
xmlFilename));
using (Stream stream = new FileStream(xmlFilename, FileMode.Open))
{
return read(stream);
}
}
internal rimeType read(Stream xmlInputStream)
{
// create an instance of the XmlSerializer class,
// specifying the type of object to be deserialized.
XmlSerializer serializer = new XmlSerializer(typeof(rimeType));
serializer.UnknownNode += new XmlNodeEventHandler(handleUnknownNode);
serializer.UnknownAttribute +=
new XmlAttributeEventHandler(handleUnknownAttribute);
// use the Deserialize method to restore the object's state
// with data from the XML document.
return (rimeType)serializer.Deserialize(xmlInputStream);
}
protected void handleUnknownNode(object sender, XmlNodeEventArgs e)
{
log.write(
string.Format(
"XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}",
e.LineNumber, e.LinePosition, e.Name, e.Text));
}
protected void handleUnknownAttribute(object sender, XmlAttributeEventArgs e)
{
log.write(
string.Format(
"XML_ERROR: Unknown Attribute at line {0} position {1} : {2}='{3}'",
e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value));
}
}
/// <summary>
/// xtractXmlReader provides bindings to the extract.xml
/// returned by the RIME server; as defined by:
/// $/Release X/Documentation/Technical/SCHEMA and
/// DTDs/nrw-rime-extract.xsd
/// </summary>
internal class ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl :
ExtractXmlReader
{
private Log log = Log.getInstance();
public rimeType read(string xmlFilename)
{
log.write(
string.Format(
"DEBUG: ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl." +
"read({0})",
xmlFilename));
using (XmlReader reader = XmlReader.Create(xmlFilename))
{
return read(reader);
}
}
public rimeType read(XmlReader reader)
{
rimeType result = new rimeType();
// a deserializer for featureClass, feature, etc, "doclets"
Dictionary<Type, XmlSerializer> serializers =
new Dictionary<Type, XmlSerializer>();
serializers.Add(typeof(featureClassType),
newSerializer(typeof(featureClassType)));
serializers.Add(typeof(featureType),
newSerializer(typeof(featureType)));
List<featureClassType> featureClasses = new List<featureClassType>();
List<featureType> features = new List<featureType>();
while (!reader.EOF)
{
if (reader.MoveToContent() != XmlNodeType.Element)
{
reader.Read(); // skip non-element-nodes and unknown-elements.
continue;
}
// skip junk nodes.
if (reader.Name.Equals("featureClass"))
{
using (
StringReader elementReader =
new StringReader(reader.ReadOuterXml()))
{
XmlSerializer deserializer =
serializers[typeof (featureClassType)];
featureClasses.Add(
(featureClassType)
deserializer.Deserialize(elementReader));
}
continue;
// ReadOuterXml advances the reader, so don't read again.
}
if (reader.Name.Equals("feature"))
{
using (
StringReader elementReader =
new StringReader(reader.ReadOuterXml()))
{
XmlSerializer deserializer =
serializers[typeof (featureType)];
features.Add(
(featureType)
deserializer.Deserialize(elementReader));
}
continue;
// ReadOuterXml advances the reader, so don't read again.
}
log.write(
"WARNING: unknown element '" + reader.Name +
"' was skipped during parsing.");
reader.Read(); // skip non-element-nodes and unknown-elements.
}
result.featureClasses = featureClasses.ToArray();
result.features = features.ToArray();
return result;
}
private XmlSerializer newSerializer(Type elementType)
{
XmlSerializer serializer = new XmlSerializer(elementType);
serializer.UnknownNode += new XmlNodeEventHandler(handleUnknownNode);
serializer.UnknownAttribute +=
new XmlAttributeEventHandler(handleUnknownAttribute);
return serializer;
}
protected void handleUnknownNode(object sender, XmlNodeEventArgs e)
{
log.write(
string.Format(
"XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}",
e.LineNumber, e.LinePosition, e.Name, e.Text));
}
protected void handleUnknownAttribute(object sender, XmlAttributeEventArgs e)
{
log.write(
string.Format(
"XML_ERROR: Unknown Attribute at line {0} position {1} : {2}='{3}'",
e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value));
}
}
}
요약하고 Google 에서이 스레드를 찾는 모든 사람에게 답을 좀 더 분명하게 만드십시오.
.NET 2 이전에는 XmlTextReader가 표준 API에서 사용할 수있는 가장 메모리 효율적인 XML 파서였습니다 (Mitch;-덕분).
.NET 2는 XmlReader 클래스를 도입했습니다. 다시 한 번 더 낫습니다. 이는 전진 전용 요소 반복기입니다 (StAX 파서와 비슷 함). (고맙습니다 Cerebrus ;-)
그리고 XML 인스턴스가 약 500k보다 클 가능성이 있다는 것을 기억하십시오. DOM을 사용하지 마십시오!
모두 건배. 키스.
SAX의 파서는 당신이 찾고있는 무슨 수 있습니다. SAX는 전체 문서를 메모리로 읽어 올 필요가 없습니다. SAX는 문서를 점진적으로 파싱하고 진행하면서 요소를 처리 할 수 있도록합니다. .NET에서 제공되는 SAX 파서가 있는지 모르겠지만 몇 가지 오픈 소스 옵션을 볼 수 있습니다.
- http://saxdotnet.sourceforge.net/
- http://www.codeguru.com/csharp/csharp/cs_data/xml/article.php/c4221
다음은 관련 게시물입니다.
Mitch가 대답 한대로 XmlReader를 사용하는 예제로이 간단한 확장 메서드를 추가하고 싶었습니다.
public static bool SkipToElement (this XmlReader xmlReader, string elementName)
{
if (!xmlReader.Read ())
return false;
while (!xmlReader.EOF)
{
if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == elementName)
return true;
xmlReader.Skip ();
}
return false;
}
그리고 사용법 :
using (var xml_reader = XmlReader.Create (this.source.Url))
{
if (!SkipToElement (xml_reader, "Root"))
throw new InvalidOperationException ("XML element \"Root\" was not found.");
if (!SkipToElement (xml_reader, "Users"))
throw new InvalidOperationException ("XML element \"Root/Users\" was not found.");
...
}
참고 URL : https://stackoverflow.com/questions/676274/what-is-the-best-way-to-parse-big-xml-in-c-sharp-code
'Program Tip' 카테고리의 다른 글
문자열 상수와 문자열 리터럴의 차이점은 무엇입니까? (0) | 2020.12.08 |
---|---|
Git에서 브랜치를 별칭으로 지정할 수 있습니까? (0) | 2020.12.08 |
Postgresql의 where 절에서 별칭 열 사용 (0) | 2020.12.08 |
Eclipse 프로젝트에서 경고 / 오류를 생성하는 폴더를 제외하는 방법은 무엇입니까? (0) | 2020.12.08 |
ifstream에서 문자열 변수로 줄 읽기 (0) | 2020.12.08 |