Управление комментариями 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());
}
}
надеюсь, это поможет вам.