Управление комментариями XML с помощью JAXB
мне нужно прочитать XML-файл и прокомментировать или раскомментировать некоторые элементы в нем на основе некоторых условий. Файл начинается так:
<elements>
    <!-- <element1 atribute="value"/> -->
    <!-- <element2 atribute="value"/> -->
    <!-- <element3 atribute="value"/> -->
    <!-- <element4 atribute="value"/> -->
    <!-- <element5 atribute="value"/> -->
</elements>
если я хочу активировать element1, element3 и element5, то файл должен выглядеть так:
<elements>
    <element1 atribute="value"/>
    <!-- <element2 atribute="value"/> -->
    <element3 atribute="value"/>
    <!-- <element4 atribute="value"/> -->
    <element5 atribute="value"/>
</elements>
другими словами, Я ищу способ добавить или удалить <!-- --> теги из каждой строки XML, которая соответствует условиям.
К сожалению, такое поведение необходимо, и не может быть изменен.
4 ответов
комментарий - это особый тип узла. Вы не можете "переключаться" из/в комментарии/государство комментарии. Я вижу здесь, по крайней мере, слишком много возможностей, как без JAXB, хотя :
путь DOM:
- проанализируйте XML-файл с помощью парсера DOM по вашему выбору (
with setIgnoringComments(false)) - получить исходные данные с каждого узла (см. комментарий.getData ())
 - создать новый узел из строки
 - заменить узел" комментарий" с вашим новым узлом (см. узел.replaceChild)
 
Не стесняйтесь спрашивать, нужен ли вам более подробный ответ. Вы должны легко найти обширную документацию для каждого шага.
путь XSLT:
вы также можете использовать XSLT, как указал @Xavier в комментариях. Проблема здесь в том, что чистое совпадение и замена выведут содержимое комментария в виде неэскапированного текста и не распознают его как реальные XML-данные. Вы можете использовать saxon, чтобы обойти это Я полагаю, с чем-то вроде этого :
<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>
Я думаю, что чтение прокомментировал и раскомментировать, делает эту проблему сложной. Более простым способом было бы добавление атрибута, с помощью которого вы можете активировать тег или деактивировать. Никакого обходного пути не потребуется, просто вам потребуется пометить его true или false.
Например:
<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 и mark element active или inactive вместо комментариев и без комментариев.
если это не делает вашу жизнь проще, всегда есть обходной путь с помощью regex, xslt и т. д..
для такой необходимости я бы четко предложил XSLT как-то XML transformation и XSLT был создан для преобразования XML содержание.
я бы тогда использовал шаблон таблицы стилей, которая предназначена для использования в качестве строкового формата, как это:
<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"><!--</xsl:text><xsl:copy-of select="."/>--<xsl:text disable-output-escaping="yes">></xsl:text>
  </xsl:template>
</xsl:stylesheet>
как вы можете видеть есть 2 режима:
- если вы выберите 
normalон просто скопирует содержимое узла - если вы выберите 
commentон будет прокомментируйте его содержание 
Итак, если мы активируем element1, element3 и element5, реальное содержание нашей таблицы стилей будет String.format(template, "normal", "comment", "normal", "comment", "normal")
в приведенном ниже фрагменте кода я использую jcabi-xml поскольку он очень прост в использовании, но вы можете использовать другую библиотеку, если хотите,XSLT является стандартом, поэтому он все равно будет работать.
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\"><!--</xsl:text><xsl:copy-of select=\".\"/>--<xsl:text disable-output-escaping=\"yes\">></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: для удобства чтения, Я отформатировал вывод
Я не думаю, что это достижимо с помощью 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, "");
                 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());
    }
}
надеюсь, это поможет вам.