使用JAXB处理XML注释

时间:2016-05-05 22:18:45

标签: java xml xml-parsing jaxb

我需要读取XML文件,并根据某些条件对其中的某些元素进行注释或取消注释。 文件开头就像这样:

element1

如果我要激活element3element5<elements> <element1 atribute="value"/> <!-- <element2 atribute="value"/> --> <element3 atribute="value"/> <!-- <element4 atribute="value"/> --> <element5 atribute="value"/> </elements> ,该文件应如下所示:

<!--

换句话说,我正在寻找一种方法来添加或删除符合条件的每个XML行中的--> fatalError :: (Show a1, Show a) => [Char] -> a -> a1 -> t fatalError s l c = error ("Error at line " ++ (show l) ++ " column " ++ (show c) ++ ": " ++ s) 个标记。
不幸的是,这种行为是必需的,无法改变。

4 个答案:

答案 0 :(得分:5)

我认为阅读评论和取消评论会使这个问题变得复杂。更简单的方法是添加属性,您可以通过该属性激活标记或停用。只要您要求将其标记为真或假,就不需要解决方法。

例如:

<elements>
    <!-- <element1 atribute="value"/> -->
    <!-- <element2 atribute="value"/> -->
    <!-- <element3 atribute="value"/> -->
    <!-- <element4 atribute="value"/> -->
    <!-- <element5 atribute="value"/> -->
</elements>

可以转化为。

<elements>
    <element1 atribute="value" isActive="false"/>
    <element2 atribute="value" isActive="false"/>
    <element3 atribute="value" isActive="false"/>
    <element4 atribute="value" isActive="false"/>
    <element5 atribute="value" isActive="false"/>
</elements>

同样,在

之下
<?xml version="1.0" encoding="UTF-8"?>
<elements>
    <element1 atribute="value"/>
    <!--<element2 atribute="value"/>-->
    <element3 atribute="value"/>
    <!--<element4 atribute="value"/>-->
    <element5 atribute="value"/>
</elements>

可以转化为。

<elements>
    <element1 atribute="value" isActive="true"/>
    <element2 atribute="value" isActive="false"/>
    <element3 atribute="value" isActive="true"/>
    <element4 atribute="value" isActive="false"/>
    <element5 atribute="value" isActive="true"/>
</elements>

这可以是解决此问题的优化方法。现在,您可以使用JAXB并将元素标记为活动或非活动,而不是注释和取消注释。

如果这不会让您的生活更轻松,那么总是使用正则表达式,xslt等进行解决方法。

答案 1 :(得分:4)

对于这种需求,我会明确建议XSLT,因为它已经创建了XML transformationXSLT来转换XML内容。

然后我会使用一个样式表的模板,这个样式表应该像这样用作String格式:

<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='2.0'>
  <xsl:template match='/'>
      <elements>
          <xsl:apply-templates select="elements/element1" mode="%s"/>
          <xsl:apply-templates select="elements/element2" mode="%s"/>
          <xsl:apply-templates select="elements/element3" mode="%s"/>
          <xsl:apply-templates select="elements/element4" mode="%s"/>
          <xsl:apply-templates select="elements/element5" mode="%s"/>
      </elements>
  </xsl:template>
  <xsl:template match='*' mode='normal'>
      <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template match='*' mode='comment'>
      <xsl:text disable-output-escaping="yes">&lt;!--</xsl:text><xsl:copy-of select="."/>--<xsl:text disable-output-escaping="yes">&gt;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

如您所见,有两种模式:

  1. 如果您选择normal,则只会复制节点的内容
  2. 如果您选择comment,则会评论其内容
  3. 如果我们激活element1element3element5,我们的样式表的真实内容将是String.format(template, "normal", "comment", "normal", "comment", "normal")

    在下面的代码段中,我使用jcabi-xml,因为它非常易于使用,但如果您愿意,可以自由使用其他库,XSLT是一个标准,因此它仍然可以使用。< / p>

    XML first = new XMLDocument(
        "<elements>\n" +
            "    <element1 atribute=\"value\"/>\n" +
            "    <element2 atribute=\"value\"/>\n" +
            "    <element3 atribute=\"value\"/>\n" +
            "    <element4 atribute=\"value\"/>\n" +
            "    <element5 atribute=\"value\"/>\n" +
            "</elements>"
    );
    String template = "<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='2.0'>\n" +
        "  <xsl:template match='/'>\n" +
        "      <elements>\n" +
        "          <xsl:apply-templates select=\"elements/element1\" mode=\"%s\"/>\n" +
        "          <xsl:apply-templates select=\"elements/element2\" mode=\"%s\"/>\n" +
        "          <xsl:apply-templates select=\"elements/element3\" mode=\"%s\"/>\n" +
        "          <xsl:apply-templates select=\"elements/element4\" mode=\"%s\"/>\n" +
        "          <xsl:apply-templates select=\"elements/element5\" mode=\"%s\"/>\n" +
        "      </elements>\n" +
        "  </xsl:template>\n" +
        "  <xsl:template match='*' mode='normal'>\n" +
        "      <xsl:copy-of select=\".\"/>\n" +
        "  </xsl:template>\n" +
        "  <xsl:template match='*' mode='comment'>\n" +
        "      <xsl:text disable-output-escaping=\"yes\">&lt;!--</xsl:text><xsl:copy-of select=\".\"/>--<xsl:text disable-output-escaping=\"yes\">&gt;</xsl:text>\n" +
        "  </xsl:template>\n" +
        "</xsl:stylesheet>";
    XML second = new XSLDocument(
        String.format(template, "normal", "comment", "normal", "comment", "normal")
    ).transform(first);
    System.out.println(second.toString());
    

    <强>输出:

    <?xml version="1.0" encoding="UTF-8"?>
    <elements>
        <element1 atribute="value"/>
        <!--<element2 atribute="value"/>-->
        <element3 atribute="value"/>
        <!--<element4 atribute="value"/>-->
        <element5 atribute="value"/>
    </elements>
    

    NB:为了便于阅读,我格式化了输出

答案 2 :(得分:3)

我不认为纯粹使用JAXB是可以实现的。这是一种使用STAX API实现的方法。我使用了类似的实现,我需要操作XML comments

    XMLInputFactory factory = XMLInputFactory.newInstance();

    XMLEventReader reader =factory.createXMLEventReader(new FileReader("input.xml"));

    XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(new FileWriter("out.xml"));


    String toggleMe = "element2";
    String regEx = "<!--(.*)-->";
    while(reader.hasNext()) {
        XMLEvent event = reader.nextEvent();

        if(event.getEventType() == XMLStreamConstants.COMMENT) {
            if(event.toString().contains(toggleMe)) {
                 String xmlElement = event.toString().replaceAll(regEx, "$1");

                 XMLEventReader elementReader = factory.createFilteredReader(factory.createXMLEventReader(new StringReader(xmlElement)), new DocElementEventFilter());
                 while(elementReader.hasNext()) {
                     writer.add(elementReader.nextEvent());
                 }
            }else {
                writer.add(event);
            }
        } else {
            writer.add(event);
        }

    }

    writer.flush();
    writer.close();
    reader.close();

这非常特定于您提供的示例xml,并且当前支持切换一个元素。您可以扩展它以切换多个元素。

以上代码也使用以下事件过滤器

class DocElementEventFilter implements EventFilter {
    @Override
    public boolean accept(XMLEvent event) {

        return !(event.isStartDocument() || event.isEndDocument());
    }
}

希望这会对你有所帮助。

答案 3 :(得分:2)

评论是一种特殊类型的节点。你不能切换&#34;切换&#34;从/到评论/未注释的状态。我在这里看到至少太多的可能性,只有在没有JAXB的情况下:

DOM方式:

  1. 使用您选择的DOM解析器(with setIgnoringComments(false)
  2. 解析XML文件
  3. 从每个节点获取原始数据(请参阅CommentgetData()
  4. 从字符串
  5. 创建新节点
  6. 替换&#34;评论&#34;具有新节点的节点(请参阅Node.replaceChild
  7. 不要犹豫,询问您是否需要更详细的答案。您应该很容易找到每个步骤的大量文档。

    XSLT方式:

    您也可以使用XSLT,正如@Xavier在评论中指出的那样。这里的问题是纯匹配和替换会将评论的内容输出为未转义的文本,并且不会将其识别为真实的XML数据。我可以使用撒克逊来避开这种情况,例如:

    <xsl:template match="comment()[contains(., 'your conditional match')]">
        <xsl:variable name="comment" select="saxon:parse(.)" as="document-node()"/>
        <xsl:copy-of select="$comment"/>
    </xsl:template>