使用 LINQ to XML 将文本和元素节点展平 xml
Flatten xml with text and element nodes using LINQ to XML
我需要以某种方式process/flatten传入xml。
来源xml:
<paragraph>
This <content styleCode="Underline">is</content>
<content styleCode="Italic">
<content styleCode="Underline">
<content styleCode="Bold">hello</content> world
</content> test</content> <content styleCode="Bold">example</content> here.
</paragraph>
目标 xml:
<paragraph>
This <content styleCode="underline">is</content> <content styleCode="italic underline bold">hello</content> <content styleCode="italic underline">world</content> <content styleCode="italic">test</content> <content styleCode="Bold">example</content> here.
</paragraph>
我更愿意使用 LINQ 来 XML 但意识到 content
元素节点旁边的子文本节点现在使它成为完全不同的任务。
我的另一个想法是通过在子节点之前插入关闭 </content>
并在其之后立即打开 <content>
来使用正则表达式在每一步中组合 innerxml ,更新 styleCode 相应的属性,然后 AddBeforeSelf
并删除旧节点。这个想法我也没有成功。
非常感谢任何想法和解决方案。
除了合并和展平 content
节点,我还必须小写合并的 styleCode 属性,这显然是最简单的部分:
XDocument xml = XDocument.Parse(sourceXml);
XName contentNode = XName.Get("content", "mynamespace");
var contentNodes = xml.Descendants(contentNode);
var renames = contentNodes.Where(x => x.Attribute("styleCode") != null);
foreach (XElement node in renames.ToArray())
{
node.Attribute("styleCode").Value = node.Attribute("styleCode").Value.ToLower();
}
您可以递归地执行此操作 - 从一个节点到另一个节点收集样式,当涉及到文本时,将其包装到包含目前找到的所有标签的内容标签中。代码如下:
static void MergeStyles(string xml)
{
XDocument doc = XDocument.Parse(xml);
var desc = doc.Document.Elements();
Go(doc.Root, new List<string>());
Console.WriteLine(target);
}
static string target = "";
static void Go(XElement node, List<string> styles)
{
foreach (var child in node.Nodes())
{
if (child.NodeType == XmlNodeType.Text)
{
if (styles.Count > 0)
{
target += string.Format(
"<content styleCode=\"{0}\">{1}</content>",
string.Join(" ", styles.Select(s => s.ToLower())),
child.ToString(SaveOptions.DisableFormatting));
}
else
{
target += child.ToString(SaveOptions.DisableFormatting);
}
}
else if (child.NodeType == XmlNodeType.Element)
{
var element = (XElement)child;
if (element.Name == "content")
{
string style = element.Attributes("styleCode").Single().Value;
styles.Add(style);
Go(element, styles);
styles.RemoveAt(styles.Count - 1);
}
}
}
}
我需要以某种方式process/flatten传入xml。
来源xml:
<paragraph>
This <content styleCode="Underline">is</content>
<content styleCode="Italic">
<content styleCode="Underline">
<content styleCode="Bold">hello</content> world
</content> test</content> <content styleCode="Bold">example</content> here.
</paragraph>
目标 xml:
<paragraph>
This <content styleCode="underline">is</content> <content styleCode="italic underline bold">hello</content> <content styleCode="italic underline">world</content> <content styleCode="italic">test</content> <content styleCode="Bold">example</content> here.
</paragraph>
我更愿意使用 LINQ 来 XML 但意识到 content
元素节点旁边的子文本节点现在使它成为完全不同的任务。
我的另一个想法是通过在子节点之前插入关闭 </content>
并在其之后立即打开 <content>
来使用正则表达式在每一步中组合 innerxml ,更新 styleCode 相应的属性,然后 AddBeforeSelf
并删除旧节点。这个想法我也没有成功。
非常感谢任何想法和解决方案。
除了合并和展平 content
节点,我还必须小写合并的 styleCode 属性,这显然是最简单的部分:
XDocument xml = XDocument.Parse(sourceXml);
XName contentNode = XName.Get("content", "mynamespace");
var contentNodes = xml.Descendants(contentNode);
var renames = contentNodes.Where(x => x.Attribute("styleCode") != null);
foreach (XElement node in renames.ToArray())
{
node.Attribute("styleCode").Value = node.Attribute("styleCode").Value.ToLower();
}
您可以递归地执行此操作 - 从一个节点到另一个节点收集样式,当涉及到文本时,将其包装到包含目前找到的所有标签的内容标签中。代码如下:
static void MergeStyles(string xml)
{
XDocument doc = XDocument.Parse(xml);
var desc = doc.Document.Elements();
Go(doc.Root, new List<string>());
Console.WriteLine(target);
}
static string target = "";
static void Go(XElement node, List<string> styles)
{
foreach (var child in node.Nodes())
{
if (child.NodeType == XmlNodeType.Text)
{
if (styles.Count > 0)
{
target += string.Format(
"<content styleCode=\"{0}\">{1}</content>",
string.Join(" ", styles.Select(s => s.ToLower())),
child.ToString(SaveOptions.DisableFormatting));
}
else
{
target += child.ToString(SaveOptions.DisableFormatting);
}
}
else if (child.NodeType == XmlNodeType.Element)
{
var element = (XElement)child;
if (element.Name == "content")
{
string style = element.Attributes("styleCode").Single().Value;
styles.Add(style);
Go(element, styles);
styles.RemoveAt(styles.Count - 1);
}
}
}
}