是否有可能XML的元素合并使用SAX(coremedia CAE过滤器)
问题描述:
假设是:是否有可能XML的元素合并使用SAX(coremedia CAE过滤器)
一个XML结构像
<span class="abbreviation">AGB<span class"explanation">Allgemeine Geschäftsbedingungen</span></span>
和改造后的结果应该是:
<abbr title="Allgemeine Geschäftsbedingungen">AGB</abbr>
我知道SAX是一个基于事件的XML解析器,并且使用类似于如下的方法:
#startElement(...)
#endElement(...)
我可以捕捉事件(如open-a-tag
,close-a-tag
),并与
#characters
我可以提取标签之间的文本。
我的问题是:
我能创造上述转换(有没有可能)?
我的问题是:
- 我可以提取的缩写文字和文字解释
- 我可以叫#startElement上的最后一个跨度标签
- ,但我不能创建的内容标签(在这种情况下文本'ABG')
答
答案是是的这是可能的!
主要参数/提示你可以从这个StackOverflow-link
这里得到的是什么必须做:
- 你要记住的状态,在此跨度标签SAX解析器位于(“类=缩写”或“类=解释”)
- 你必须提取标记的内容(这可以用
#character
方法来完成) - 当你知道SAX解析器和内容的状态,你可以N新建一个新的
abbr
-tag - 所有其他标签,有没有任何修饰
为了完整这里加入是coremedia CAE过滤器的源代码:
import com.coremedia.blueprint.cae.richtext.filter.FilterFactory;
import com.coremedia.xml.Filter;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class GlossaryFilter extends Filter implements FilterFactory {
private static final String SPAN = "span";
private static final String CLASS = "class";
private boolean isAbbreviation = false;
private boolean isExplanation = false;
private String abbreviation;
private String currentUri;
private boolean spanExplanationClose = false;
private boolean spanAbbreviationClose = false;
@Override
public Filter getInstance(final HttpServletRequest request, final HttpServletResponse response) {
return new GlossaryFilter();
}
@Override
public void startElement(final String uri, final String localName, final String qName,
final Attributes attributes) throws SAXException {
if (isSpanAbbreviationTag(qName, attributes)) {
isAbbreviation = true;
} else if (isSpanExplanationTag(qName, attributes)) {
isExplanation = true;
currentUri = uri;
} else {
super.startElement(uri, localName, qName, attributes);
}
}
private boolean isSpanExplanationTag(final String qName, final Attributes attributes) {
//noinspection OverlyComplexBooleanExpression
return StringUtils.isNotEmpty(qName) && qName.equalsIgnoreCase(SPAN) && (
attributes.getLength() > 0) && attributes.getValue(CLASS).equals("explanation");
}
private boolean isSpanAbbreviationTag(final String qName, final Attributes attributes) {
//noinspection OverlyComplexBooleanExpression
return StringUtils.isNotEmpty(qName) && qName.equalsIgnoreCase(SPAN) && (
attributes.getLength() > 0) && attributes.getValue(CLASS).equals("abbreviation");
}
@Override
public void endElement(final String uri, final String localName, final String qName)
throws SAXException {
if (spanExplanationClose) {
spanExplanationClose = false;
} else if (spanAbbreviationClose) {
spanAbbreviationClose = false;
} else {
super.endElement(uri, localName, qName);
}
}
@Override
public void characters(final char[] ch, final int start, final int length) throws SAXException {
if (isAbbreviation && isExplanation) {
final String explanation = new String(ch, start, length);
final AttributesImpl newAttributes = createAttributes(explanation);
writeAbbrTag(newAttributes);
changeState();
} else if (isAbbreviation && !isExplanation) {
abbreviation = new String(ch, start, length);
} else {
super.characters(ch, start, length);
}
}
private void changeState() {
isExplanation = false;
isAbbreviation = false;
spanExplanationClose = true;
spanAbbreviationClose = true;
}
@SuppressWarnings("TypeMayBeWeakened")
private void writeAbbrTag(final AttributesImpl newAttributes) throws SAXException {
super.startElement(currentUri, "abbr", "abbr", newAttributes);
super.characters(abbreviation.toCharArray(), 0, abbreviation.length());
super.endElement(currentUri, "abbr", "abbr");
}
private AttributesImpl createAttributes(final String explanation) {
final AttributesImpl newAttributes = new AttributesImpl();
newAttributes.addAttribute(currentUri, "title", "abbr:title", "CDATA", explanation);
return newAttributes;
}
}
有趣的东西是在方法:
startElement(...)
endElement(...)
characters(...)
的startElement(...)
在这里,您存储在其标签上的SAX解析器所在的国家(更详细:您存储的状态,这跨度标签(在“class = abbreviation”或“class = explanation”)被打开。
-
isAbbreviation
与“类=简称” -
isExplanation
与“类=的解释”
只储存状态的打开跨度标签打开的跨度标签。提到的span标签不会被处理/过滤(结果是,它们将被删除)。每个其他标签都是在不进行过滤的情况下处理的,它们将不加修改地应用(即else
-block)。
的endElement(...)
在这里,你只想要处理除(所提到的跨度标签)的每个标签。所有这些标签都不加修改地应用(else
-block)。如果SAX解析器位于一个封闭的跨度标签(与“阶级=缩写”或“类=的解释”),你想要什么都不做(除了店面的状态)
字符(...)
在这个方法中,发生了魔术(用解析器创建一个标签)。根据不同的状态:
- SAX解析器位于具有“类=的解释”的跨度标签(这意味着有一个与“阶级=简称”日前通过一个开放的跨度标签) - >分支
(isAbbreviation && isExplanation)
- SAX解析器位于第一区间标签(跨度标签与“类=简称”) - >分支(
isAbbreviation && !isExplanation
) - 您在任何其他标记找到每一个其它字符 - >分支
else
为状态3.
简单复制文本您找到
国有2.
提取与“阶级=简称”跨度标签的内容供以后使用
的状态3
- 用“class = explanation”解释span标签的内容“
- 创建为
abbr
- 标签的属性(title=....
) - 写入新
abbr
- 标签(而不是两个跨度标签) - 集我只使用SAX状态
如果你处理的是非常大的输入 - 太大而不适合内存,或者处理的时间关键处理在纳秒数量的情况下,否则你只会增加复杂性...... – Adam
这听起来像是XSLT的工作。 –
嗯,我必须使用SAX,因为它是一个模块(核心媒体框架的过滤器) – SleepyX667