gpt4 book ai didi

java - 仅生成特定深度和限制列表的 XML

转载 作者:太空宇宙 更新时间:2023-11-04 10:05:14 25 4
gpt4 key购买 nike

对于一个基于 XSD 文件生成 XML 文件的项目,我想自动生成文档。 *

在本文档中,我列出了 XSD 中定义的不同元素。对于每个元素,我想展示该元素的一个示例。问题是,XML 示例可能很长并且包含很多子项。因此我想通过以下方式缩短示例:

  • 限制显示深度
  • 限制列表中元素的数量

对于根元素,该示例可能如下所示:

<root>
<elements>
<element>...<element>
<element>...<element>
<element>...<element>
...
</elements>
</root>

我的方法:

为了从 XSD 生成类并生成和验证 XML 文件,我使用 JAXB。但我不知道如何编码非根元素。因此,我使用 XStream 生成示例。

为了限制 XML 示例,我尝试装饰 PrettyPrintWriter,但这似乎相当麻烦。这两个装饰器可以在我的回答中看到。我只是没想到会关心这样一个(常见?)功能的库的内部结构。

有更简单的方法吗? (我也可以使用 XStream 之外的其他库,或者根本不使用。)

*我的方法受到 Spring Auto Rest Docs 的影响

最佳答案

为了限制显示的深度,我创建了以下 XStream WriterWrapper。例如,该类可以包装 PrettyPrintWriter 并确保包装的编写器仅接收高于给定深度阈值的节点。

public class RestrictedPrettyPrintWriter extends WriterWrapper {

private final ConverterLookup converterLookup;
private final int maximalDepth;
private int depth;

public RestrictedPrettyPrintWriter(HierarchicalStreamWriter sw, ConverterLookup converterLookup, int maximalDepth) {
super(sw);
this.converterLookup = converterLookup;
this.maximalDepth = maximalDepth;
}

@Override public void startNode(String name, Class clazz) {
Converter converter = this.converterLookup.lookupConverterForType(clazz);
boolean isSimpleType = converter instanceof SingleValueConverter;
_startNode(name, !isSimpleType);
}

@Override public void startNode(String name) {
_startNode(name, false);
}

@Override public void endNode() {
if (_isLessDeepThanMaximalDepth() || _isMaximalDepthReached()) {
super.endNode();
}
depth--;
}

@Override public void addAttribute(String key, String value) {
if (_isLessDeepThanMaximalDepth() || _isMaximalDepthReached()) {
super.addAttribute(key, value);
}
}

@Override public void setValue(String text) {
if (_isLessDeepThanMaximalDepth() || _isMaximalDepthReached()) {
super.setValue(text);
}
}

/**
* @param name name of the new node
* @param isComplexType indicates if the element is complex or contains a single value
*/
private void _startNode(String name, boolean isComplexType) {
depth++;
if (_isLessDeepThanMaximalDepth()) {
super.startNode(name);
} else if (_isMaximalDepthReached()) {
super.startNode(name);
/*
* set the placeholder value now
* setValue() will never be called for complex types
*/
if (isComplexType) {
super.setValue("...");
}
}
}

private boolean _isMaximalDepthReached() {
return depth == maximalDepth;
}

private boolean _isLessDeepThanMaximalDepth() {
return depth < maximalDepth;
}

}

为了限制列表,我第一次尝试修改 XStream CollectionConverter。但这种方法不够通用,因为隐式列表不使用此转换器。

因此,我创建了另一个 WriterWrapper 来计算同名元素的连续出现次数。

public class RestrictedCollectionWriter extends WriterWrapper {

private final int maxConsecutiveOccurences;

private int depth;
/** Contains one element per depth.
* More precisely: the current element and its parents.
*/
private Map < Integer, Elements > elements = new HashMap < > ();

public RestrictedCollectionWriter(HierarchicalStreamWriter sw, int maxConsecutiveOccurences) {
super(sw);
this.maxConsecutiveOccurences = maxConsecutiveOccurences;
}

@Override public void startNode(String name, Class clazz) {
_startNode(name);
}

@Override public void startNode(String name) {
_startNode(name);
}

@Override public void endNode() {
if (_isCurrentElementPrintable()) {
super.endNode();
}
depth--;
}

@Override public void addAttribute(String key, String value) {
if (_isCurrentElementPrintable()) {
super.addAttribute(key, value);
}
}

@Override public void setValue(String text) {
if (_isCurrentElementPrintable()) {
super.setValue(text);
}
}

/**
* @param name name of the new node
*/
private void _startNode(String name) {
depth++;
Elements currentElement = this.elements.getOrDefault(depth, new Elements());
this.elements.put(depth, currentElement);

Elements parent = this.elements.get(depth - 1);
boolean parentPrintable = parent == null ? true : parent.isPrintable();
currentElement.setName(name, parentPrintable);

if (currentElement.isPrintable()) {
super.startNode(name);
}
}

private boolean _isCurrentElementPrintable() {
Elements currentElement = this.elements.get(depth);
return currentElement.isPrintable();
}

/**
* Evaluates if an element is printable or not.
* This is based on the concurrent occurences of the element's name
* and if the parent element is printable or not.
*/
private class Elements {
private String name = "";
private int concurrentOccurences = 0;
private boolean parentPrintable;

public void setName(String name, boolean parentPrintable) {
if (this.name.equals(name)) {
concurrentOccurences++;
} else {
concurrentOccurences = 1;
}
this.name = name;
this.parentPrintable = parentPrintable;
}

public boolean isPrintable() {
return parentPrintable && concurrentOccurences <= maxConsecutiveOccurences;
}
}
}

以下 list 显示了如何使用这两个类。

XStream xstream = new XStream(new StaxDriver());
StringWriter sw = new StringWriter();
PrettyPrintWriter pw = new PrettyPrintWriter(sw);
RestrictedCollectionWriter cw = new RestrictedCollectionWriter(pw, 3);
xstream.marshal(objectToMarshal, new RestrictedPrettyPrintWriter(cw, xstream.getConverterLookup(), 3));

关于java - 仅生成特定深度和限制列表的 XML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53020137/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com