0

I am generating a XML format file using String Builder. the file will look something like this :-

  StringBuilder strBldr = new StringBuilder();
  strBldr.AppendLine("<Root>");
  strBldr.AppendLine("<ProductDetails>");
  strBldr.AppendLine("<PId>" + lblproductid.Text + "</PId>");
  strBldr.AppendLine("<PDesc>" + strtxtProductDesc + "</PDesc>");
  strBldr.AppendLine("</ProductDetails>");
  strBldr.AppendLine("</Root>");

This is in for loop, so it may contain many product details. Now I need to split this string if it exceeds the limited length suppose 100. Till now it was easy. I am able to split this using following method:-

 public static IEnumerable<string> SplitByLength(this string str, int maxLength)
 {
        for (int index = 0; index < str.Length; index += maxLength)
        {
            yield return str.Substring(index, Math.Min(maxLength, str.Length - index));
        }
  }

But the thing is, this method just simply splits the string if it finds length is greater that 100. but I need to be sure if it tries to split from middle of the xml node, then it should find the just above <ProductDetails> node and split from there. what should I add to the code to achieve this?

4

2 回答 2

3

How about if lblproductid.Text contains, for ex, &, < or >?

Therefore I would use a real xml parser instead of forming it by hand.

var xElem = new XElement("Root",
                    new XElement("ProductDetails",
                        new XElement("PId", lblproductid.Text),
                        new XElement("PDesc",strtxtProductDesc)));

var xml = xElem.ToString();

output would be:

<Root>
  <ProductDetails>
    <PId>aaa</PId>
    <PDesc>aaa</PDesc>
  </ProductDetails>
</Root>

PS: You can loop for ProductDetails and count the total length.

于 2013-04-18T14:03:50.270 回答
2

You definitely should use XDocument instead of string to construct and query XML data.

You could create an extension method on XDocument class that will split by length:

public static class XDocumentExtensions
{
    public static IEnumerable<string> SplitByLength(this XDocument source, string elementName, int maxLength)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (string.IsNullOrEmpty(elementName))
            throw new ArgumentException("elementName cannot be null or empty.", "elementName");
        if (maxLength <= 0)
            throw new ArgumentException("maxLength has to be greater than 0.", "maxLength");

        return SplitByLengthImpl(source, elementName, maxLength);
    }

    private static IEnumerable<string> SplitByLengthImpl(XDocument source, string elementName, int maxLength)
    {
        var builder = new StringBuilder();

        foreach (var element in source.Root.Elements(elementName))
        {
            var currentElementString = element.ToString();
            if (builder.Length + currentElementString.Length > maxLength)
            {
                if (builder.Length > 0)
                {
                    yield return builder.ToString();
                    builder.Clear();
                }
                else
                {
                    throw new ArgumentException(
                        "source document contains element with length greater than maxLength", "source");
                }
            }

            builder.AppendLine(currentElementString);
        }
        if (builder.Length > 0)
            yield return builder.ToString();
    }
}

And then use it like that:

var parts = doc.SplitByLength("ProductDetails", 200).ToList();
于 2013-04-18T14:26:08.060 回答