Search code examples
c#.netxmlxelement

Replacing XElement content with XElement


Is there a way to selectively replace XElement content with other XElements?

I have this XML:

<prompt>
   There is something I want to tell you.[pause=3]
   You are my favorite caller today.[pause=1]
   Have a great day!
</prompt>

And I want to render it as this:

<prompt>
   There is something I want to tell you.<break time="3s"/>
   You are my favorite caller today.<break time="1s"/>
   Have a great day!
</prompt>

I need to replace the placeholders with actual XElements, but when I try to alter the content of an XElement, .NET of course escapes all of the angle brackets. I understand why the content would normally need to be correctly escaped, but I need to bypass that behavior and inject XML directly into content.

Here's my code that would otherwise work.

MatchCollection matches = Regex.Matches(content, @"\[(\w+)=(\d+)]");
foreach (XElement element in voiceXmlDocument.Descendants("prompt"))
{
    if (matches[0] == null)
        continue;
    element.Value = element.Value.Replace(matches[0].Value, @"<break time=""5s""/>");
}

This is a work in progress, so don't worry so much about the validity of the RegEx pattern, as I will work that out later to match several conditions. This is proof of concept code and the focus is on replacing the placeholders as described. I only included the iteration and RegEx code here to illustrate that I need to be able to do this to a whole document that is already populated with content.


Solution

  • You can use XElement.Parse() method:

    First, get the outer xml of your XElement, for example,

    string outerXml = element.ToString();
    

    The you have exactly this string to work with:

    <prompt>
      There is something I want to tell you.[pause=3]
      You are my favorite caller today.[pause=1]
      Have a great day!
    </prompt>
    

    Then you can do your replacement

    outerXml = outerXml.Replace(matches[0].Value, @"<break time=""5s""/>");
    

    Then you can parse it back:

    XElement repElement = XElement.Parse(outerXml);
    

    And, finally, replace original XElement:

    element.ReplaceWith(repElement);