有没有办法选择性地用其他XElements替换XElement内容?
我有这个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>
我希望将其渲染为:
<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>
我需要用实际的XElements替换占位符,但是当我尝试更改XElement的内容时,.NET当然会转义所有的尖括号。我理解为什么通常需要正确转义内容,但我需要绕过这种行为并将XML直接注入内容。
这是我的代码,否则会有效。
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""/>");
}
这是一项正在进行中的工作,所以不要过多担心RegEx模式的有效性,因为我将在以后解决这个问题,以满足几个条件。这是概念代码的证明,重点是如上所述替换占位符。我这里只包含了迭代和RegEx代码,以说明我需要能够对已经填充了内容的整个文档执行此操作。
答案 0 :(得分:2)
您可以使用XElement.Parse()
方法:
首先,获取XElement的外部xml,例如
string outerXml = element.ToString();
您正好使用此字符串:
<prompt>
There is something I want to tell you.[pause=3]
You are my favorite caller today.[pause=1]
Have a great day!
</prompt>
然后你可以替换
outerXml = outerXml.Replace(matches[0].Value, @"<break time=""5s""/>");
然后你可以解析它:
XElement repElement = XElement.Parse(outerXml);
最后,替换原来的XElement:
element.ReplaceWith(repElement);
答案 1 :(得分:0)
所有这一切的关键是XText
,它允许您将文本作为元素处理。
这是循环:
foreach (XElement prompt in voiceXmlDocument.Descendants("prompt"))
{
string text = prompt.Value;
prompt.RemoveAll();
foreach (string phrase in text.Split('['))
{
string[] parts = phrase.Split(']');
if (parts.Length > 1)
{
string[] pause = parts[0].Split('=');
prompt.Add(new XElement("break", new XAttribute("time", pause[1])));
// add a + "s" if you REALLY want it, but then you have to get rid
// of it later in some other code.
}
prompt.Add(new XText(parts[parts.Length - 1]));
}
}
这是最终结果
<prompt>
There is something I want to tell you.<break time="3" />
You are my favorite caller today.<break time="1" />
Have a great day!
</prompt>
答案 2 :(得分:0)
class Program
{
static void Main(string[] args)
{
var 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>";
var voiceXmlDocument = XElement.Parse(xml);
var pattern = new Regex(@"\[(\w+)=(\d+)]");
foreach (var element in voiceXmlDocument.DescendantsAndSelf("prompt"))
{
var matches = pattern.Matches(element.Value);
foreach (var match in matches)
{
var matchValue = match.ToString();
var number = Regex.Match(matchValue, @"\d+").Value;
var newValue = string.Format(@"<break time=""{0}""/>", number);
element.Value = element.Value.Replace(matchValue, newValue);
}
}
Console.WriteLine(voiceXmlDocument.ToString());
}
}
答案 3 :(得分:0)
foreach (XElement element in voiceXmlDocument.Descendants("prompt").ToArray())
{
// convert the element to a string and see to see if there are any instances
// of pause placeholders in it
string elementAsString = element.ToString();
MatchCollection matches = Regex.Matches(elementAsString, @"\[pause=(\d+)]");
if (matches == null || matches.Count == 0)
continue;
// if there were no matches or an empty set, move on to the next one
// iterate through the indexed matches
for (int i = 0; i < matches.Count; i++)
{
int pauseValue = 0; // capture the original pause value specified by the user
int pauseMilliSeconds = 1000; // if things go wrong, use a 1 second default
if (matches[i].Groups.Count == 2) // the value is expected to be in the second group
{
// if the value could be parsed to an integer, convert it from 1/8 seconds to milliseconds
if (int.TryParse(matches[i].Groups[1].Value, out pauseValue))
pauseMilliSeconds = pauseValue * 125;
}
// replace the specific match with the new <break> tag content
elementAsString = elementAsString.Replace(matches[i].Value, string.Format(@"<break time=""{0}ms""/>", pauseMilliSeconds));
}
// finally replace the element by parsing
element.ReplaceWith(XElement.Parse(elementAsString));
}
答案 4 :(得分:0)
噢,天哪,你们比我想象的要快!
卫生署!不管怎样,不妨发布我的解决方案!
foreach (var element in xml.Descendants("prompt"))
{
Queue<string> pauses = new Queue<string>(Regex.Matches(element.Value, @"\[pause *= *\d+\]")
.Cast<Match>()
.Select(m => m.Value));
Queue<string> text = new Queue<string>(element.Value.Split(pauses.ToArray(), StringSplitOptions.None));
element.RemoveAll();
while (text.Any())
{
element.Add(new XText(text.Dequeue()));
if (pauses.Any())
element.Add(new XElement("break", new XAttribute("time", Regex.Match(pauses.Dequeue(), @"\d+"))));
}
}
对于每个提示元素,正则表达式匹配所有暂停并将它们放入队列中。
然后使用这些提示来分隔内部文本并抓住其他内容。将文本放入队列中。
使用RemoveAll清除元素中的所有数据,然后迭代分隔数据并将其重新添加为适当的数据类型。当您添加新属性时,可以使用Regex从原始匹配中获取数字值。