是否可以将 XML-Elements 与 SAX(coremedia CAE 过滤器)合并

Is it possible to merge XML-Elements with SAX (coremedia CAE filter)

给出的是:

一个XML结构像

<span class="abbreviation">AGB<span class"explanation">Allgemeine Geschäftsbedingungen</span></span>

转换后的结果应该是:

<abbr title="Allgemeine Geschäftsbedingungen">AGB</abbr>

我知道 SAX 是一个基于事件的 XML-解析器,并且具有类似

的方法

我可以捕获事件(例如 open-a-tagclose-a-tag)并使用

我可以提取标签之间的文本。

我的问题是:

我可以创建上述转换(可能吗)?

我的问题是:

答案是有可能!

主要argument/hint你可以从这里得到Whosebug-link

这是必须要做的事情:

  1. 你必须记住 sax 解析器所在的 span-tag 状态("class=abbreviation" 或 "class=explanation")
  2. 你必须提取标签的内容(这可以用#character方法完成)
  3. 当您知道 sax 解析器的状态和内容时,您可以创建一个新的 abbr-tag
  4. 所有其他标签,必须不加任何修改地接受

为了完整起见,这里是 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(...)

开始元素(...)

此处存储 sax-parser 所在标记的状态(更详细:存储打开哪个 span-tag("class=abbreviation" 或 "class=explanation")的状态。

  • isAbbreviation 对于带有 "class=abbreviation"
  • 的打开的 span-tag
  • isExplanation 对于带有 "class=explanation"
  • 的打开的 span-tag

你只存储状态。提到的 span-tags 不会是 processed/filtered (结果是,它们将被删除)。每个其他标签都经过处理而没有过滤,它们将在没有修改的情况下应用(即 else-block)。

endElement(...)

在这里你只想处理除了(提到的span-tags)之外的每个标签。所有这些标签都没有修改地应用(else-block)。如果 sax 解析器位于封闭的 span-tag(带有 "class=abbreviation" 或 "class=explanation"),您什么都不做(除了存储状态)

字符数(...)

在这个方法中,魔术(使用解析器创建标签)发生了。取决于州:

  1. Sax 解析器位于带有 "class=explanation" 的 span-tag 中(这意味着之前传递了一个带 "class=abbreviation" 的开放 span-tag)--> branch (isAbbreviation && isExplanation)
  2. Sax解析器位于第一个span-tag(带有"class=abbreviation"的span-tag)--> branch (isAbbreviation && !isExplanation)
  3. 您在任何其他标签中找到的所有其他字符 --> 分支 else

状态 3。

只需复制您找到的文本

状态 2。

使用"class=abbreviation"提取span-tag的内容供以后使用

状态 3。

  • 使用"class=explanation"提取span-tag的内容
  • abbr-标签 (title=....) 创建属性
  • 写入新的 abbr-tag(而不是两个 span-tags)
  • 设置状态