Я программно пишу множество SDL-файлов для геосервера, которые по своей сути являются XML-файлами. Я использую {xml2}, и хотя я получаю правильный формат в небольшом репрексе (каждый тег в одной строке и с отступом), в моем полном примере это больше не работает.
Я бы предположил, что геосервер не заботится о переносах строк, но администраторы обслуживаемого сервиса настаивают на том, что файл SLD не работает, если в нем нет правильных отступов.
Как я могу заставить выходной файл разместить один тег в строке с правильным отступом?
library(xml2)
x <- read_xml("<parent></parent>")
xml_add_child(x, "child", type = "child")
child <- xml_find_first(x, ".//child")
for (i in 1:5) {
xml_add_child(child, "small_child",
label = i,
.where = i)
}
x
#> {xml_document}
#> <parent>
#> [1] <child type = "child">\n <small_child label = "1"/>\n <small_child label = "2 ...
write_xml(x, "small_reprex.sld")
Created on 2024-04-17 with reprex v2.1.0
Выходной файл с правильными отступами:
<?xml version = "1.0" encoding = "UTF-8"?>
<parent>
<child type = "child">
<small_child label = "1"/>
<small_child label = "2"/>
<small_child label = "3"/>
<small_child label = "4"/>
<small_child label = "5"/>
</child>
</parent>
library(xml2)
xml_file <- read_xml('<?xml version = "1.0" encoding = "UTF-8"?>
<sld:StyledLayerDescriptor xmlns = "http://www.opengis.net/sld" xmlns:sld = "http://www.opengis.net/sld" xmlns:ogc = "http://www.opengis.net/ogc" xmlns:gml = "http://www.opengis.net/gml" version = "1.0.0">
<sld:NamedLayer>
<sld:Name>SLD template for qualitative rasters</sld:Name>
<sld:UserStyle>
<sld:Name>SLD template for qualitative rasters</sld:Name>
<sld:FeatureTypeStyle>
<sld:Name>name</sld:Name>
<sld:Rule>
<sld:RasterSymbolizer>
</sld:RasterSymbolizer>
</sld:Rule>
</sld:FeatureTypeStyle>
</sld:UserStyle>
</sld:NamedLayer>
</sld:StyledLayerDescriptor>')
namedlayer <- xml_find_first(xml_file, ".//sld:NamedLayer")
namelayer <- xml_find_first(namedlayer, ".//sld:Name")
xml_text(namelayer) <- "Name changed"
userstyle <- xml_find_first(namedlayer, ".//sld:UserStyle")
namelayer <- xml_find_first(userstyle, ".//sld:Name")
xml_text(namelayer) <- "Name changed"
symb <- xml_find_first(xml_file, ".//sld:RasterSymbolizer")
xml_add_child(symb, "sld:ColorMap", type = "values", .where = 1)
colormap <- xml_find_first(xml_file, ".//sld:ColorMap")
labels <- letters[1:5]
colors <- viridis::turbo(5)
for (i in seq_along(labels)) {
xml_add_child(colormap, "sld:ColorMapEntry",
color = colors[[i]],
quantity = i,
label = labels[[i]],
.where = i)
}
write_xml(xml_file, "reprex.sld", format = c("format", "as_xml"))
Created on 2024-04-17 with reprex v2.1.0
А вот выходной файл, в котором все записи карты цветов помещаются в одну строку:
<?xml version = "1.0" encoding = "UTF-8"?>
<sld:StyledLayerDescriptor xmlns = "http://www.opengis.net/sld" xmlns:sld = "http://www.opengis.net/sld" xmlns:ogc = "http://www.opengis.net/ogc" xmlns:gml = "http://www.opengis.net/gml" version = "1.0.0">
<sld:NamedLayer>
<sld:Name>Name changed</sld:Name>
<sld:UserStyle>
<sld:Name>Name changed</sld:Name>
<sld:FeatureTypeStyle>
<sld:Name>name</sld:Name>
<sld:Rule>
<sld:RasterSymbolizer>
<sld:ColorMap type = "values"><sld:ColorMapEntry color = "#30123BFF" quantity = "1" label = "a"/><sld:ColorMapEntry color = "#28BBECFF" quantity = "2" label = "b"/><sld:ColorMapEntry color = "#A2FC3CFF" quantity = "3" label = "c"/><sld:ColorMapEntry color = "#FB8022FF" quantity = "4" label = "d"/><sld:ColorMapEntry color = "#7A0403FF" quantity = "5" label = "e"/></sld:ColorMap></sld:RasterSymbolizer>
</sld:Rule>
</sld:FeatureTypeStyle>
</sld:UserStyle>
</sld:NamedLayer>
</sld:StyledLayerDescriptor>
Я понятия не имею, как это сделать. Я просто искал, что такое XSLT, но не могу понять, чем это может мне помочь. Спасибо!
Я обновил ответ ссылкой на расширение пакета xml2 для преобразования XML-документов путем применения таблицы стилей xslt.
Вот общий XSLT, который будет делать отступы для любого XML-файла правильного формата.
Входной XML + XSLT => Выходной XML
Вам просто нужно научиться выполнять этот XSLT на вашем любимом языке программирования.
Ознакомьтесь с расширением пакета xml2 для преобразования XML-документов с помощью таблицы стилей xslt: xslt: Преобразования языка расширяемых таблиц стилей
XSLT
<?xml version = "1.0"?>
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "xml" indent = "yes" encoding = "utf-8" omit-xml-declaration = "no"/>
<xsl:strip-space elements = "*"/>
<xsl:template match = "node()|@*">
<xsl:copy>
<xsl:apply-templates select = "node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Это сработало. Спасибо! Совершенно новый мир для меня... Я добавил ответ о том, как реализовать его в R с помощью пакета {xslt}, для других, у кого такая же проблема.
Это реализация в R с использованием пакета {xslt} и шаблона, предоставленного в ответе, помеченном как правильный:
library(xml2)
library(xslt)
xml_file <- read_xml('<?xml version = "1.0" encoding = "UTF-8"?>
<sld:StyledLayerDescriptor xmlns = "http://www.opengis.net/sld" xmlns:sld = "http://www.opengis.net/sld" xmlns:ogc = "http://www.opengis.net/ogc" xmlns:gml = "http://www.opengis.net/gml" version = "1.0.0">
<sld:NamedLayer>
<sld:Name>SLD template for qualitative rasters</sld:Name>
<sld:UserStyle>
<sld:Name>SLD template for qualitative rasters</sld:Name>
<sld:FeatureTypeStyle>
<sld:Name>name</sld:Name>
<sld:Rule>
<sld:RasterSymbolizer>
</sld:RasterSymbolizer>
</sld:Rule>
</sld:FeatureTypeStyle>
</sld:UserStyle>
</sld:NamedLayer>
</sld:StyledLayerDescriptor>')
namedlayer <- xml_find_first(xml_file, ".//sld:NamedLayer")
namelayer <- xml_find_first(namedlayer, ".//sld:Name")
xml_text(namelayer) <- "Name changed"
userstyle <- xml_find_first(namedlayer, ".//sld:UserStyle")
namelayer <- xml_find_first(userstyle, ".//sld:Name")
xml_text(namelayer) <- "Name changed"
symb <- xml_find_first(xml_file, ".//sld:RasterSymbolizer")
xml_add_child(symb, "sld:ColorMap", type = "values")
colormap <- xml_find_first(xml_file, ".//sld:ColorMap")
labels <- letters[1:5]
colors <- viridis::turbo(5)
for (i in seq_along(labels)) {
xml_add_child(colormap, "sld:ColorMapEntry",
color = colors[[i]],
quantity = i,
label = labels[[i]],
.where = i)
}
style <- read_xml('<?xml version = "1.0"?>
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "xml" indent = "yes" encoding = "utf-8" omit-xml-declaration = "no"/>
<xsl:strip-space elements = "*"/>
<xsl:template match = "node()|@*">
<xsl:copy>
<xsl:apply-templates select = "node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>')
xml_styled <- xml_xslt(xml_file, style)
write_xml(xml_styled, "reprex.sld")
Вы можете использовать XSLT на этапе постобработки, чтобы добиться правильного отступа.