문제

혼합된 내용을 얻는 가장 좋은 방법은 무엇입니까? 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 방법도 기존의 일반 방법과 비교했습니다. 시스템.Xml Greg가 제안한 방법.변형은 흥미롭고 내가 기대했던 것과는 달랐습니다. 가장 느린 방법은 다음과 같습니다. 가장 빠른 것보다 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 - Terry(0.360초)
  6. 배열의 String.Concat - 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 (에 대한 시스템.Xml 방법) 또는 XDocument (다른 모든 사람들을 위해).

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

리더 생성:

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

return reader.ReadInnerXml();

문자열 연결로 집계:

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

스트링빌더:

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());

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


결론

성능이 중요한 경우(예:XML이 많고 자주 구문 분석됨) 다니엘을 이용하세요 CreateReader 방법은 매번.몇 가지 쿼리만 수행하는 경우 Mike의 보다 간결한 Aggregate 방법을 사용하는 것이 좋습니다.

많은 노드(아마도 100개)가 있는 큰 요소에 XML을 사용하는 경우 아마도 다음을 사용하는 것의 이점을 보기 시작할 것입니다. StringBuilder Aggregate 메서드를 초과하지만 초과하지는 않음 CreateReader.나는 생각하지 않는다 Join 그리고 Concat 큰 목록을 큰 배열로 변환하면 패널티가 발생하기 때문에 이러한 조건에서는 메소드가 더 효율적입니다(여기서는 더 작은 목록에서도 분명합니다).

다른 팁

나는 이것이 훨씬 더 나은 방법이라고 생각합니다(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())
  • 문자열을 연결할 때 Aggregate는 메모리와 성능이 비효율적입니다.
  • Join("", sth)을 사용하면 Concat보다 두 배 더 큰 문자열 배열을 사용합니다...그리고 코드에서 꽤 이상해 보입니다.
  • +=를 사용하는 것은 매우 이상해 보이지만 '+'를 사용하는 것보다 훨씬 나쁘지는 않습니다. 할당 결과가 사용되지 않고 컴파일러에 의해 안전하게 제거될 수 있으므로 아마도 동일한 코드에 최적화될 것입니다.
  • StringBuilder는 매우 중요하며 불필요한 "상태"가 좋지 않다는 것은 모두가 알고 있습니다.

나는 이것을 사용하게되었습니다 :

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

개인적으로 글을 마무리하게 되었어요 InnerXml Aggregate 메서드를 사용하는 확장 메서드:

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

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

var innerXml = myXElement.InnerXml();

@그렉:답변을 완전히 다른 답변으로 편집한 것으로 보입니다.내 대답은 '예'입니다. System.Xml을 사용하여 이 작업을 수행할 수 있지만 LINQ to XML에 익숙해지기를 바랐습니다.

왜 내가 필요한 것을 얻기 위해 XElement의 .Value 속성을 사용할 수 없는지 다른 사람이 궁금해할 경우를 대비해 원래 답변을 아래에 남겨 두겠습니다.

@그렉:Value 속성은 모든 하위 노드의 모든 텍스트 내용을 연결합니다.따라서 body 요소에 텍스트만 포함되어 있으면 작동하지만 XHTML이 포함되어 있으면 모든 텍스트가 함께 연결되지만 태그는 표시되지 않습니다.

// 단순히 시작 및 끝 요소 태그를 자르는 것이 Regex를 사용하는 것이 더 빠를 수 있습니다.

var content = element.ToString();
var matchBegin = Regex.Match(content, @"<.+?>");
content = content.Substring(matchBegin.Index + matchBegin.Length);          
var matchEnd = Regex.Match(content, @"</.+?>", RegexOptions.RightToLeft);
content = content.Substring(0, matchEnd.Index);

doc.ToString() 또는 doc.ToString(SaveOptions)이 작업을 수행합니다.보다 http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.tostring(v=vs.110).aspx

LINQ를 사용하는 대신 System.Xml 네임스페이스 개체를 사용하여 여기서 작업을 완료할 수 있습니까?이미 언급했듯이 XmlNode.InnerXml이 바로 여러분에게 필요한 것입니다.

궁금합니다(b+=를 없애고 b+만 있다는 점에 주목하세요).

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

보다 약간 덜 효율적일 수 있습니다.

string.Join( "", t.Element.Nodes()
                  .Select( n => n.ToString() ).ToArray() );

100% 확실하지는 않지만... Reflector의 Aggregate() 및 string.Join()을 살펴보니...I 생각하다 반환 값을 추가하는 Aggregate로 읽었으므로 기본적으로 다음을 얻습니다.

문자열 = 문자열 + 문자열

string.Join과 비교했을 때 FastStringAllocation 같은 것에 대한 언급이 있어서 Microsoft 직원이 거기에 추가 성능 향상을 적용했을 수도 있다고 생각됩니다.물론 내 .ToArray()는 이를 부정한다고 부르지만, 나는 또 다른 제안을 제시하고 싶었습니다.

알잖아?가장 좋은 방법은 CDATA로 돌아가는 것입니다. :( 여기에서 솔루션을 찾고 있지만 CDATA가 가장 간단하고 저렴하며 개발하기에 가장 편리하지는 않다고 생각합니다.

var innerXmlAsText= XElement.Parse(xmlContent)
                    .Descendants()
                    .Where(n => n.Name.LocalName == "template")
                    .Elements()
                    .Single()
                    .ToString();

당신을 위해 일을 할 것입니다

public static string InnerXml(this XElement xElement)
{
    //remove start tag
    string innerXml = xElement.ToString().Trim().Replace(string.Format("<{0}>", xElement.Name), "");
    ////remove end tag
    innerXml = innerXml.Trim().Replace(string.Format("</{0}>", xElement.Name), "");
    return innerXml.Trim();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top