2

I am writing a tool that takes in an XML file, edits it by adding in elements and then saves it. The tricky bit is that the XML files need to be maintained human readable, and in this case that doesn't mean perfect formatting.

The input XElement contains many parameters such as this:

<Parameter key="lorem"> <Vector> <Value>2</Value><Value>3</Value> </Vector>     </Parameter>
<Parameter key="lorem"> <Vector> <Value>2</Value><Value>3</Value> </Vector> </Parameter>
<Parameter key="lorem"> <Vector> <Value>2</Value><Value>3</Value> </Vector> </Parameter>
<Parameter key="lorem"> <Vector> <Value>2</Value><Value>3</Value> </Vector>    </Parameter>
<Parameter key="lorem">
    <Parameter key="ipsum">
        <Parameter key="dolor">
            <Vector> <Value>3</Value> <Value>4</Value> </Vector>
        </Parameter>
    </Parameter>
</Parameter

I want all XElements with name "Vector" and "Value" to disable indenting, but all XElements with name "Parameter" to maintain indenting.

Since my code isn't allowed to mess up any of the existing formatting, I am forced to use LoadOptions.PreserveWhitespace on the source document. This, however, forces all XElements that I add to the document to loose any formatting. Is there a way I can force a particular XElement to apply formatting, even though the whole document doesn't do it?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
ValtsBlukis
  • 458
  • 4
  • 11

3 Answers3

1

This looks like the answer you are after.

The key to solving this problem is to write a recursive function that iterates through the XML tree, writing the various elements and attributes to specially created XmlWriter objects. There is an 'outer' XmlWriter object that writes indented XML, and an 'inner' XmlWriter object that writes non-indented XML.

The recursive function initially uses the 'outer' XmlWriter, writing indented XML, until it sees the TextBlock element. When it encounters the TextBlock element, it creates the 'inner' XmlWriter object, writing the child elements of the TextBlock element to it. It also writes white space to the 'inner' XmlWriter.

When the 'inner' XmlWriter object is finished with writing the TextBlock element, the text that the writer wrote is written to the 'outer' XmlWriter using the WriteRaw method.

Community
  • 1
  • 1
bitbonk
  • 48,890
  • 37
  • 186
  • 278
0

You would probably have to inherit from XmlWriter to encode the serialization rules and then save the XDocument using this custom XmlWriter.

Pawel
  • 31,342
  • 4
  • 73
  • 104
0

One unpleasant but possibly "least evil of the alternatives" is to add the desired whitespace yourself when you create the element. That way when you save you can just preserve all whitespace, and it'll be fine. It does mean working out how to do the indentation yourself (working out how far down the tree you are and adding the right number spaces) but it shouldn't be too painful.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks! I did attempt this before asking the question, but I realized that the code started to look very messy and I realized I can't easily guarantee reliability in all possible circumstances. – ValtsBlukis Nov 14 '12 at 08:56
  • @ValtsBlukis: I wouldn't expect it to be *that* messy - and where would the reliability fail? – Jon Skeet Nov 14 '12 at 09:06
  • I have a few special use cases. All XML's that my tool deals with are hand-written. Which means they can contain any combination of indenting. Some blocks are not indented as much as others, some lines have comments and have the parameter appended after the comment etc. The one I gave is just a fragment from the middle of the XML. However after a re-thought I think I should be able to come up with a recursive algorithm that manages this by keeping track of element depth level and building some form of a depth level -> indent size map. I didn't realize how to get current indent sizes. – ValtsBlukis Nov 14 '12 at 09:27