[.net] XElement의 InnerXml을 얻는 가장 좋은 방법은 무엇입니까?

body아래 코드에서 혼합 요소 의 내용을 얻는 가장 좋은 방법은 무엇입니까 ? 요소에 XHTML 또는 텍스트가 포함될 수 있지만 내용을 문자열 형식으로 원합니다. XmlElement유형은 가지고 InnerXml난 후 정확히 무엇 속성을.

작성된 코드는 거의 내가 원하는 않지만, 주변 포함 <body></body>내가 원하지 않는 요소를.

XDocument doc = XDocument.Load(new StreamReader(s));
var templates = from t in doc.Descendants("template")
                where t.Attribute("name").Value == templateName
                select new
                {
                   Subject = t.Element("subject").Value,
                   Body = t.Element("body").ToString()
                };



답변

제안 된 솔루션 중 어떤 것이 가장 잘 수행되는지 확인하고 싶었 기 때문에 비교 테스트를 수행했습니다. 관심이 없으면 LINQ 메서드를 Greg가 제안한 일반 구형 System.Xml 메서드 와 비교했습니다 . 가장 느린 방법 은 가장 빠른 방법 보다 3 배 이상 느린 변형이 흥미롭고 예상했던 것과 다릅니다. .

결과는 가장 빠르거나 느리게 정렬됩니다.

  1. CreateReader-인스턴스 헌터 (0.113 초)
  2. 평범한 오래된 System.Xml-Greg Hurlman (0.134 초)
  3. 문자열 연결로 집계-Mike Powell (0.324 초)
  4. StringBuilder-Vin (0.333 초)
  5. String.Join on array-Terry (0.360 초)
  6. 배열의 문자열-Marcin Kosieradzki (0.364)

방법

20 개의 동일한 노드 ( ‘힌트’라고 함)가있는 단일 XML 문서를 사용했습니다.

<hint>
  <strong>Thinking of using a fake address?</strong>
  <br />
  Please don't. If we can't verify your address we might just
  have to reject your application.
</hint>

위의 초로 표시된 숫자는 20 개 노드의 “내부 XML”을 1000 회 연속으로 추출하여 평균 (평균) 5 회 실행 한 결과입니다. XML을로드하고 XmlDocument( System.Xml 메서드의 경우) 구문 분석하는 데 걸리는 시간은 포함하지 않았습니다.XDocument (다른 모든 것의 경우 .

내가 사용한 LINQ 알고리즘은 다음과 같습니다. (C #-모두 XElement“부모”를 취하고 내부 XML 문자열을 반환합니다)

리더 만들기 :

var reader = parent.CreateReader();
reader.MoveToContent();

return reader.ReadInnerXml();

문자열 연결로 집계 :

return parent.Nodes().Aggregate("", (b, node) => b += node.ToString());

StringBuilder :

StringBuilder sb = new StringBuilder();

foreach(var node in parent.Nodes()) {
    sb.Append(node.ToString());
}

return sb.ToString();

배열의 String.Join :

return String.Join("", parent.Nodes().Select(x => x.ToString()).ToArray());

배열의 String.Concat :

return String.Concat(parent.Nodes().Select(x => x.ToString()).ToArray());

노드에서 .InnerXml을 호출하기 때문에 여기에 “Plain old System.Xml”알고리즘을 표시하지 않았습니다.


결론

성능이 중요한 경우 (예 : 많은 XML, 자주 구문 분석) 매번 Daniel의 CreateReader방법을 사용 합니다 . 몇 가지 쿼리를 수행하는 경우 Mike의 더 간결한 집계 방법을 사용할 수 있습니다.

많은 노드 (아마도 100)가있는 큰 요소에서 XML을 사용하는 경우 아마도 StringBuilderAggregate 메서드 를 사용하는 것의 이점을 볼 수 있지만 over는 아닙니다 CreateReader. 큰 목록을 큰 배열로 변환하는 것에 대한 패널티 (여기서는 작은 목록에서는 명백 함)로 인해 이러한 조건에서 JoinConcat메소드가 더 효율적 이라고 생각하지 않습니다 .


답변

나는 이것이 훨씬 더 나은 방법이라고 생각합니다 (VB에서는 번역하기가 어렵지 않아야 함).

XElement x가 주어지면 :

Dim xReader = x.CreateReader
xReader.MoveToContent
xReader.ReadInnerXml


답변

XElement에서이 “확장”방법을 사용하는 것은 어떻습니까? 나를 위해 일했다!

public static string InnerXml(this XElement element)
{
    StringBuilder innerXml = new StringBuilder();

    foreach (XNode node in element.Nodes())
    {
        // append node's xml string to innerXml
        innerXml.Append(node.ToString());
    }

    return innerXml.ToString();
}

또는 Linq를 조금 사용하십시오

public static string InnerXml(this XElement element)
{
    StringBuilder innerXml = new StringBuilder();
    doc.Nodes().ToList().ForEach( node => innerXml.Append(node.ToString()));

    return innerXml.ToString();
}

참고 : 위 코드는 element.Nodes()반대로 사용해야 합니다 element.Elements(). 둘 사이의 차이점을 기억하는 것이 매우 중요합니다. element.Nodes()당신처럼 모든 것을 제공 XText, XAttribute등,하지만 XElement단지 요소.


답변

최상의 접근 방식을 발견하고 입증 한 사람들에게 모든 정당한 인정을 받았으므로 (감사합니다!) 확장 방법으로 싸여 있습니다.

public static string InnerXml(this XNode node) {
    using (var reader = node.CreateReader()) {
        reader.MoveToContent();
        return reader.ReadInnerXml();
    }
}


답변

간단하고 효율적으로 유지하십시오.

String.Concat(node.Nodes().Select(x => x.ToString()).ToArray())
  • 집계는 문자열을 연결할 때 메모리 및 성능 비효율적입니다
  • Join ( “”, sth)을 사용하면 Concat보다 두 배 더 큰 문자열 배열을 사용하고 있습니다. 코드에서 매우 이상하게 보입니다.
  • + =를 사용하는 것은 매우 이상해 보이지만 ‘+’를 사용하는 것보다 그리 나쁘지는 않습니다. 아마도 동일한 코드에 최적화 될 것입니다. 할당 결과가 사용되지 않고 컴파일러에 의해 안전하게 제거 될 수 있습니다.
  • StringBuilder는 매우 필수적입니다. 모든 사람은 불필요한 “상태”가 짜증나다는 것을 알고 있습니다.

답변

나는 이것을 사용하여 끝났다.

Body = t.Element("body").Nodes().Aggregate("", (b, node) => b += node.ToString());


답변

개인적으로 InnerXmlAggregate 메소드를 사용하여 확장 메소드를 작성했습니다 .

public static string InnerXml(this XElement thiz)
{
   return thiz.Nodes().Aggregate( string.Empty, ( element, node ) => element += node.ToString() );
}

내 클라이언트 코드는 이전 System.Xml 네임 스페이스와 마찬가지로 간결합니다.

var innerXml = myXElement.InnerXml();