问题:
我一直在尝试解析 xml,并为 XML 中的每个节点创建一个对象。
问题:
由于我的 xml 具有任意顺序的节点,并且有些节点是其他节点的子节点,因此我很难在不使用 .net 1.1 和 XmlNode 类的情况下从逻辑上解析它们。
注意:我希望只使用 XMLReader,因为我仅限于 .Net Standard 1.0,并且不想安装任何额外的库。 (参见此处:https://learn.microsoft.com/en-us/dotnet/standard/net-standard)
目前我为每个 xml 节点创建一个对象,每个对象包含一个我希望添加到的子组件列表,如果它找到一个子节点。但是我似乎无法递归搜索 xml 并将结构正确生成到列表/列表列表中。
我的代码:
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApp1
{
class Program
{
static List<UIComponent> components = new List<UIComponent>();
static void Main(string[] args)
{
String path = "C:\\Users\\admin\\Desktop\\test.xml";
parseXML(path);
}
private static UIComponent addToLowestChild(UIComponent parent, UIComponent child)
{
for(int i=0;i<parent.getChildren().Count;++i)
{
if (parent.getChildren().Count > 0)
{
foreach (UIComponent kid1 in parent.getChildren())
{
if (kid1.getChildren().Count > 0)
{
addToLowestChild(kid1, child);
}
}
}
}
return parent;
}
private static UIComponent ChildTest(int depth,UIComponent parent,UIComponent child)
{
//i=depth for item 4, if i is set to 1 first
for (int i = 1; i < depth; ++i)
{
if (parent.getChildren().Count > 0)
{
if (i > 1)
{
ChildTest(i, parent.getChildren()[parent.getChildren().Count - 1], child);
}
else
{
parent.getChildren()[parent.getChildren().Count - 1].addChild(child);
break;
}
}
else
{
parent.addChild(child);
break;
}
}
return parent;
}
private static void parseXML(string path)
{
//read the xml file into one string
string[] lines = System.IO.File.ReadAllLines(path);
string xmlContent = "";
foreach (string line in lines)
{
xmlContent += line;
}
UIComponent currentComponent = null;
//parse the xml content
using (XmlReader reader = XmlReader.Create(new StringReader(xmlContent)))
{
while (reader.Read())
{
int currentDepth = 0;
// Console.WriteLine(reader.Name+" depth:"+reader.Depth);
if (reader.Depth > 0) //ignore ground level elements such as <XML> and <UI>
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (currentComponent == null || reader.Depth==currentDepth)
{
currentComponent = new UIComponent(reader.Name);
}
else
{
UIComponent childComponent = new UIComponent(reader.Name);
//currentComponent.addChild(childComponent);
ChildTest(reader.Depth,currentComponent,childComponent);
}
break;
case XmlNodeType.Text:
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
break;
case XmlNodeType.Comment:
break;
case XmlNodeType.EndElement:
if (reader.Depth == 1 && currentComponent!=null)
{
components.Add(currentComponent);
currentComponent = null;
}
break;
default: break;
}
}
}
}
}
我的测试数据
<?xml version="1.0" encoding="UTF-8"?>
<UI>
<window x="5">
<Button2 value="">
<Button3 y="">
</Button3>
<Button4>
<Button6 value=""></Button6>
<Button5 value=""></Button5>
</Button4>
</Button2>
</window>
<window></window>
<heading></heading>
</UI>
输出:
-Window
|-Button 2
|-- Button 3
|-- Button 4
|-- Button 6
|-- Button 5
-Window
-Heading
我想要的:
-Window
|-Button 2
|-- Button 3
|-- Button 4
|-- Button 6
|-- Button 5
-Window
-Heading
最佳答案
您只需要维护一个当前正在处理的节点的堆栈。任何时候你点击 StartElement ,您创建一个新节点,读取属性,将其添加到父节点或根节点列表,如果它不是空元素(如 <window /> ),则将其插入堆栈。当你点击 EndElement您只需弹出(删除)堆栈的最后一个元素。栈顶元素代表当前正在处理的节点。
将其付诸实践,将 XML 解析为像这样的简单类列表:
class Node
{
public string Name;
public List<Node> Children = new List<Node>();
public Dictionary<string, string> Attributes = new Dictionary<string, string>();
public override string ToString() => Name;
}
可能是这样的:
static List<Node> ParseXML(string xmlContent)
{
using (var reader = XmlReader.Create(new StringReader(xmlContent)))
{
var rootNodes = new List<Node>();
var nodeStack = new Stack<Node>();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
var node = new Node { Name = reader.Name };
if (reader.MoveToFirstAttribute())
{
// Read the attributes
do
{
node.Attributes.Add(reader.Name, reader.Value);
}
while (reader.MoveToNextAttribute());
// Move back to element
reader.MoveToElement();
}
var nodes = nodeStack.Count > 0 ? nodeStack.Peek().Children : rootNodes;
nodes.Add(node);
if (!reader.IsEmptyElement)
nodeStack.Push(node);
break;
case XmlNodeType.EndElement:
nodeStack.Pop();
break;
}
}
return rootNodes;
}
关于c# - 将 XML 结构重建为递归样式列表/XMLReader 替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46073941/
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
我有一大串格式化数据(例如JSON),我想使用Psychinruby同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
是否有类似“RVMuse1”或“RVMuselist[0]”之类的内容而不是键入整个版本号。在任何时候,我们都会看到一个可能包含5个或更多ruby的列表,我们可以轻松地键入一个数字而不是X.X.X。这也有助于rvmgemset。 最佳答案 这在RVM2.0中是可能的=>https://docs.google.com/document/d/1xW9GeEpLOWPcddDg_hOPvK4oeLxJmU3Q5FiCNT7nTAc/edit?usp=sharing-知道链接的任何人都可以发表评论
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
“输出”是一个序列化的OpenStruct。定义标题try(:output).try(:data).try(:title)结束什么会更好?:) 最佳答案 或者只是这样:deftitleoutput.data.titlerescuenilend 关于ruby-on-rails-更好的替代方法try(:output).try(:data).try(:name)?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最