【发布时间】:2022-10-03 05:02:13
【问题描述】:
我需要解析一个我不知道整个结构的 xml 文件,但我知道一些我希望解析的节点和属性,假设我有这个文件结构:
<Root>
//lots and lots of irrelevant info here
<Name>
<EffectiveName Value=\"My-Name\" />
<UserName Value=\"\" />
<Annotation Value=\"\" />
<MemorizedFirstClipName Value=\"\" />
</Name>
//lots and lots of irrelevant info here
<NotNeeded1>
<NotNeeded2>
<NotNeeded13>
<KeyTracks>
<KeyTrack Id=\"43\">
<Notes>
<MidiNoteEvent Time=\"0\" Duration=\"0.5\" Velocity=\"120\" VelocityDeviation=\"0\" OffVelocity=\"64\" Probability=\"1\" IsEnabled=\"true\" NoteId=\"73\" />
</Notes>
<MidiKey Value=\"0\" />
</KeyTrack>
<KeyTrack Id=\"44\">
<Notes>
<MidiNoteEvent Time=\"0.5\" Duration=\"0.5\" Velocity=\"120\" VelocityDeviation=\"0\" OffVelocity=\"64\" Probability=\"1\" IsEnabled=\"true\" NoteId=\"75\" />
</Notes>
<MidiKey Value=\"1\" />
</KeyTrack>
<KeyTrack Id=\"45\">
<Notes>
<MidiNoteEvent Time=\"1\" Duration=\"0.5\" Velocity=\"120\" VelocityDeviation=\"0\" OffVelocity=\"64\" Probability=\"1\" IsEnabled=\"true\" NoteId=\"77\" />
</Notes>
<MidiKey Value=\"2\" />
</KeyTrack>
<KeyTrack Id=\"46\">
<Notes>
<MidiNoteEvent Time=\"1.5\" Duration=\"0.5\" Velocity=\"120\" VelocityDeviation=\"0\" OffVelocity=\"64\" Probability=\"1\" IsEnabled=\"true\" NoteId=\"79\" />
</Notes>
<MidiKey Value=\"3\" />
</KeyTrack>
</KeyTracks>
</NotNeeded1>
</NotNeeded2>
</NotNeeded13>
//lots and lots of irrelevant info here
</Root>
它比那要大得多,但只是为了举例。
我希望将文件提取并解析为以下对象:
CustomObject.class
public class CustomObject{
private String effectiveName;
private List<KeyTrack> keyTracks;
}
KeyTracks.class
public class KeyTrack {
private Integer keyTrackId;
private MidiNoteEvent midiNoteEvent;
private Integer midiKey;
}
MidiNoteEvent .class
public class MidiNoteEvent {
private Double time;
private Integer velocity;
private Double duration;
private Boolean isEnabled;
}
我正在尝试尽可能通用,因此如果我需要添加另一个节点或属性,我将不必更改我的解析器,因此 switch/case 或 if/else 不适合我的情况可能有数百个节点和添加,如果需要解析额外的信息,我不想更改多个类。
我试图为我需要的节点创建一个枚举,但我找不到能够正确抓取节点的最佳位置。
这些是我现在的解析器功能
private final Map<String, Object> map;
@Override
public ProjectTrack parse(Node node) {
parseToMap(node);
return mapper.convertValue(map, CustomObject.class);
}
private void parseToMap(Node node){
if(Arrays.stream(RelevantMidiTrackNodes.values()).anyMatch(
e -> e.getNodeName().equals(node.getNodeName()))
){
System.out.print(node.getNodeName() + \": \");
for (int i = 0; i < node.getAttributes().getLength(); i++) {
Attr attribute = (Attr)node.getAttributes().item(i);
System.out.print(attribute.getNodeName() + \" - \" + attribute.getValue() + \", \");
map.put(attribute.getNodeName(), attribute.getValue());
}
System.out.println();
}
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node currentNode = nodeList.item(i);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
//calls this method for all the children which is Element
parseToMap(currentNode);
}
}
}
更新:
更新了文件本身,我需要的节点可以更深 10 个节点,并且父节点无关紧要,所以我正在寻找一种方法来提取第 1、第 2 级和第 10 级的节点。
在我的示例中,将 EffectiveName 提取到字符串并将 KeyTracks 提取到列表
-
使用 XPath 获取所需元素然后解组它们可能会更好。此外,该问题应提供一个minimal reproducible example,包括最小完整的 xml 结构。
-
我上传了我需要的 xml 的结构以及我需要将其解析为的对象。如果您能详细说明,不确定到底缺少什么,谢谢