Reputation: 4848
I have an XElement that I have to parse to remove the white space in the closing tag. My code looks like this:
var stringBuilder = new StringBuilder();
using (var stringWriter = new StringWriter(stringBuilder))
{
xelement.Save(stringWriter);
}
stringBuilder.Replace(" />", "/>");
var xml = stringBuilder.ToString();
Basically, I'm making a stringbuilder and replacing the unneeded white space. The resulting string looks fine, except it has the XML declaration. I know that on an XmlWriter, I can omit the declaration with OmitXmlDeclaration
but StringWriter doesn't have this.
Is there a way to do this, or do I need to manually parse out the declaration from the resulting string?
For clarity, here is the before and after XML:
// Before
<actionitem actiontaken="none" target="0" targetvariable="0">
<windowname>Popup Window</windowname>
<windowposx>-1</windowposx>
<windowposy>-1</windowposy>
<windowwidth>-1</windowwidth>
<windowheight>-1</windowheight>
<noscrollbars>false</noscrollbars>
<nomenubar />
<notoolbar />
<noresize />
<nostatus />
<nolocation />
<browserWnd />
</actionitem>
// After
<?xml version="1.0" encoding="utf-16"?>
<actionitem actiontaken="none" target="0" targetvariable="0">
<windowname>Popup Window</windowname>
<windowposx>-1</windowposx>
<windowposy>-1</windowposy>
<windowwidth>-1</windowwidth>
<windowheight>-1</windowheight>
<noscrollbars>false</noscrollbars>
<nomenubar/>
<notoolbar/>
<noresize/>
<nostatus/>
<nolocation/>
<browserWnd/>
</actionitem>
EDIT: For those that asked, this is for a Department of Defense project. Their specifications are locked in. That means, no white space in the closing tag, no matter how much I protest. Regardless of what's right or not, they don't want it, and they're signing the paycheck. I just try to accommodate them.
Upvotes: 3
Views: 8114
Reputation: 9218
Disclaimer: this answer applies to Kevin J and Kevin J alone. Do not perform string manipulation on XML.
If you still want to use the StringBuilder/StringWriter you can wire the StringWriter
(which is a TextWriter
) through a XmlWriter
:
var xe = new XElement("test",
new XElement("child1"),
new XElement("child2"));
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
using (var xr = XmlWriter.Create(writer, new XmlWriterSettings()
{
OmitXmlDeclaration = true
}))
{
xe.Save(xr);
}
sb.Replace(" />", "/>");
As for the Replace
I wrote a function that should be a bit more resilient against corner cases (comments, CData). It should also use less cycles and consume less memory.
static void StripClosingWhitespace(StringBuilder sb)
{
var inComment = false;
var inCData = false;
for (var i = 0; i < sb.Length; i++)
{
var c = sb[i];
if (inComment)
{
if (c == '>' && sb[i - 1] == '-' && sb[i - 2] == '-')
inComment = false;
}
else if (inCData)
{
if (c == '>' && sb[i - 1] == ']' && sb[i - 2] == ']')
inCData = false;
}
else if (i > 2 && c == '-' && sb[i - 1] == '-' && sb[i - 2] == '!' && sb[i - 3] == '<')
{
inComment = true;
}
else if (i > 7 &&
c == '[' &&
sb[i - 1] == 'A' && sb[i - 2] == 'T' && sb[i - 3] == 'A' && sb[i - 4] == 'D' && sb[i - 5] == 'C' &&
sb[i - 6] == '[' && sb[i - 7] == '!' && sb[i - 8] == '<')
{
inCData = true;
}
else if (i > 2 && c == '>' && sb[i - 1] == '/' && char.IsWhiteSpace(sb[i - 2]))
{
sb.Remove(i - 2, 1);
i--;
}
else
{
// Do nothing
}
}
}
Upvotes: 2
Reputation: 273244
Use ToString()
instead of Save()
. That eliminates the need for the StringBuilder too.
string xml = xelement.ToString(); // no declaration element added
xml = xml.Replace(" />", "/>"); // if you really think you must
Upvotes: 3