Преобразование SLD из 1.1 в 1.0 через python

В настоящее время я пытаюсь преобразовать SLD, тип XML, из одной версии в другую, написав скрипт Python. Я бьюсь об него головой уже почти две недели, и у меня мало прогресса. Я действительно новичок в python и буду признателен за любые предложения!
По сути, мне нужно включить это….

<?xml version="1.0" encoding="ISO-8859-1"?>
<StyledLayerDescriptor version="1.1.0" xmlns="http://www.opengis.net/sld" 
xmlns:ogc="http://www.opengis.net/ogc" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xlink="http://www.w3.org/1999/xlink" 
xsi:schemaLocation="http://www.opengis.net/sld 
http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" 
xmlns:se="http://www.opengis.net/se">
<NamedLayer>
<se:Name>Custom_Landuse</se:Name>
<se:Description>
  <se:Title>Custom_Landuse</se:Title>
  <se:Abstract>A Land Use style</se:Abstract>
</se:Description>
<UserStyle>
  <se:Name>County Electoral Division</se:Name>
  <se:FeatureTypeStyle>
    <se:Rule>
      <se:Name>Woods</se:Name>
      <ogc:Filter>
        <ogc:PropertyIsEqualTo>
          <ogc:PropertyName>AREA_CODE</ogc:PropertyName>
          <ogc:Literal>CED</ogc:Literal>
        </ogc:PropertyIsEqualTo>
      </ogc:Filter>
      <se:MinScaleDenominator>65000</se:MinScaleDenominator>
      <se:MaxScaleDenominator>150000</se:MaxScaleDenominator>
      <se:PolygonSymbolizer>
        <se:Name>Woods</se:Name>
        <se:Fill>
          <se:SvgParameter name="fill">#228B22</se:SvgParameter>
          <se:SvgParameter name="fill-opacity">0</se:SvgParameter>
        </se:Fill>
        <se:Stroke>
          <se:SvgParameter name="stroke">#ADFF2F</se:SvgParameter>
          <se:SvgParameter name="stroke-opacity"></se:SvgParameter>
          <se:SvgParameter name="stroke-width">1.4</se:SvgParameter>
          <se:SvgParameter name="stroke-linejoin">round</se:SvgParameter>
          <se:SvgParameter name="stroke-linecap">round</se:SvgParameter>
        </se:Stroke>
      </se:PolygonSymbolizer>
      <se:TextSymbolizer>
        <se:Name>Woods</se:Name>
         <se:Label>
           <ogc:PropertyName>NAME</ogc:PropertyName>
         </se:Label>
         <se:Font>
           <se:SvgParameter name="font-family">Sans-Serif</se:SvgParameter>
           <se:SvgParameter name="font-style">normal</se:SvgParameter>
           <se:SvgParameter name="font-size">20</se:SvgParameter>
           <se:SvgParameter name="font-weight">bold</se:SvgParameter>
         </se:Font>
         <se:Fill>
           <se:SvgParameter name="fill">#ADFF2F</se:SvgParameter>
         </se:Fill>
      </se:TextSymbolizer>
    </se:Rule>
    <se:Rule>
      <se:Name>Grass</se:Name>
      <ogc:Filter>
        <ogc:PropertyIsEqualTo>
          <ogc:PropertyName>AREA_CODE</ogc:PropertyName>
          <ogc:Literal>CED</ogc:Literal>
        </ogc:PropertyIsEqualTo>
      </ogc:Filter>
      <se:MinScaleDenominator>65000</se:MinScaleDenominator>
      <se:MaxScaleDenominator>150000</se:MaxScaleDenominator>
      <se:PolygonSymbolizer>
        <se:Name>Grass</se:Name>
        <se:Fill>
          <se:SvgParameter name="fill">#90EE90</se:SvgParameter>
          <se:SvgParameter name="fill-opacity">0</se:SvgParameter>
        </se:Fill>
        <se:Stroke>
          <se:SvgParameter name="stroke">#6B8E23</se:SvgParameter>
          <se:SvgParameter name="stroke-opacity"></se:SvgParameter>
          <se:SvgParameter name="stroke-width">1.4</se:SvgParameter>
          <se:SvgParameter name="stroke-linejoin">round</se:SvgParameter>
          <se:SvgParameter name="stroke-linecap">round</se:SvgParameter>
        </se:Stroke>
      </se:PolygonSymbolizer>
      <se:TextSymbolizer>
        <se:Name>Grass</se:Name>
         <se:Label>
           <ogc:PropertyName>NAME</ogc:PropertyName>
         </se:Label>
         <se:Font>
           <se:SvgParameter name="font-family">Sans-Serif</se:SvgParameter>
           <se:SvgParameter name="font-style">normal</se:SvgParameter>
           <se:SvgParameter name="font-size">20</se:SvgParameter>
           <se:SvgParameter name="font-weight">bold</se:SvgParameter>
         </se:Font>
         <se:Fill>
           <se:SvgParameter name="fill">#6B8E23</se:SvgParameter>
         </se:Fill>
      </se:TextSymbolizer>
    </se:Rule>
  </se:FeatureTypeStyle>
</UserStyle>

в это

<?xml version="1.0" encoding="UTF-8"?> 
<StyledLayerDescriptor version="1.0.0" xmlns="http://www.opengis.net/sld" 
xmlns:ogc="http://www.opengis.net/ogc" 
xmlns:gml="http://www.opengis.net/gml"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xlink="http://www.w3.org/1999/xlink" 
xsi:schemaLocation="http://www.opengis.net/sld 
http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd">
<NamedLayer>
<Name>Custom_Landuse</Name>
<UserStyle>
  <Name>Land Use</Name>
  <FeatureTypeStyle>
    <Rule>
      <Name>Woods</Name>
      <Title>Woods - 1:65,000 to 1:150,000</Title>
      <Abstract>A Land Use style</Abstract>
      <ogc:Filter>
        <ogc:PropertyIsEqualTo>
          <ogc:PropertyName>AREA_CODE</ogc:PropertyName>
          <ogc:Literal>CED</ogc:Literal>
        </ogc:PropertyIsEqualTo>
      </ogc:Filter>
      <MinScaleDenominator>65000</MinScaleDenominator>
      <MaxScaleDenominator>150000</MaxScaleDenominator>
      <PolygonSymbolizer>
        <Fill>
          <CssParameter name="fill">#228B22</CssParameter>
          <CssParameter name="fill-opacity">1</CssParameter>
        </Fill>
        <Stroke>
          <CssParameter name="stroke">#ADFF2F</CssParameter>
          <CssParameter name="stroke-opacity"></CssParameter>
          <CssParameter name="stroke-width">1.4</CssParameter>
          <CssParameter name="stroke-linejoin">round</CssParameter>
          <CssParameter name="stroke-linecap">round</CssParameter>
        </Stroke>
      </PolygonSymbolizer>
      <TextSymbolizer>
         <Label>
           <ogc:PropertyName>NAME</ogc:PropertyName>
         </Label>
         <Font>
           <CssParameter name="font-family">Sans-Serif</CssParameter>
           <CssParameter name="font-style">normal</CssParameter>
           <CssParameter name="font-size">20</CssParameter>
           <CssParameter name="font-weight">bold</CssParameter>
         </Font>
         <Fill>
           <CssParameter name="fill">#ADFF2F</CssParameter>
         </Fill>
      </TextSymbolizer>
    </Rule>
    <Rule>
      <Name>Grass</Name>
      <Title>Grass - 1:65,000 to 1:150,000</Title>
      <Abstract>A Land Use style</Abstract>
      <ogc:Filter>
        <ogc:PropertyIsEqualTo>
          <ogc:PropertyName>AREA_CODE</ogc:PropertyName>
          <ogc:Literal>CED</ogc:Literal>
        </ogc:PropertyIsEqualTo>
      </ogc:Filter>
      <MinScaleDenominator>65000</MinScaleDenominator>
      <MaxScaleDenominator>150000</MaxScaleDenominator>
      <PolygonSymbolizer>
        <Fill>
          <CssParameter name="fill">#90EE90</CssParameter>
          <CssParameter name="fill-opacity">1</CssParameter>
        </Fill>
        <Stroke>
          <CssParameter name="stroke">#6B8E23</CssParameter>
          <CssParameter name="stroke-opacity"></CssParameter>
          <CssParameter name="stroke-width">1.4</CssParameter>
          <CssParameter name="stroke-linejoin">round</CssParameter>
          <CssParameter name="stroke-linecap">round</CssParameter>
        </Stroke>
      </PolygonSymbolizer>
      <TextSymbolizer>
         <Label>
           <ogc:PropertyName>NAME</ogc:PropertyName>
         </Label>
         <Font>
           <CssParameter name="font-family">Sans-Serif</CssParameter>
           <CssParameter name="font-style">normal</CssParameter>
           <CssParameter name="font-size">20</CssParameter>
           <CssParameter name="font-weight">bold</CssParameter>
         </Font>
         <Fill>
           <CssParameter name="fill">#6B8E23</CssParameter>
         </Fill>
      </TextSymbolizer>
    </Rule>
  </FeatureTypeStyle>
</UserStyle>

У меня сейчас есть этот код

import xml.etree.ElementTree as ET
from lxml import etree

# Run once per file
StyledLayerDescriptor = ET.Element("StyledLayerDescriptor",version="1.0", )
NamedLayer = ET.SubElement(StyledLayerDescriptor, "NamedLayer")
Name = ET.SubElement(NamedLayer, "Name")
Line_county_electoral_division_region"
UserStyle = ET.SubElement(NamedLayer, "UserStyle")
Name = ET.SubElement(UserStyle, "Name")"
FeatureTypeStyle = ET.SubElement(UserStyle, "FeatureTypeStyle")

# Run once per rule in file
Rule = ET.SubElement(FeatureTypeStyle, "Rule")
Name = ET.SubElement(Rule, "Name")
Line_county_electoral_division_region"
Title = ET.SubElement(Rule, "Title")
Abstract = ET.SubElement(Rule, "Abstract")
Filter = ET.SubElement(Rule, "Filter")
PropertyIsEqualTo = ET.SubElement(Filter, "PropertyIsEqualTo")
PropertyName = ET.SubElement(PropertyIsEqualTo, "PropertyName")
Literal = ET.SubElement(PropertyIsEqualTo, "Literal")
MinScaleDenominator = ET.SubElement(Rule, "MinScaleDenominator")
MaxScaleDenominator = ET.SubElement(Rule, "MaxScaleDenominator")
PolygonSymbolizer = ET.SubElement(Rule, "PolygonSymbolizer")
Fill = ET.SubElement(PolygonSymbolizer, "Fill")
Stroke = ET.SubElement(PolygonSymbolizer, "Stroke")
TextSymbolizer = ET.SubElement(Rule, "PolygonSymbolizer")
Label = ET.SubElement(TextSymbolizer, "Label")
PropertyName = ET.SubElement(Label, "PropertyName")
Front = ET.SubElement(TextSymbolizer, "Front")
Fill = ET.SubElement(TextSymbolizer, "Fill")

ET.SubElement(Fill, "CssParameter", name="fill")
ET.SubElement(Fill, "CssParameter", name="fill-opacity")
ET.SubElement(Stroke, "CssParameter", name="stroke")
ET.SubElement(Stroke, "CssParameter", name="stroke-opacity")
ET.SubElement(Stroke, "CssParameter", name="stroke-width")
ET.SubElement(Stroke, "CssParameter", name="stroke-linejoin")"
ET.SubElement(Stroke, "CssParameter", name="stroke-linecap")
ET.SubElement(Front, "CssParameter", name="font-family")
ET.SubElement(Front, "CssParameter", name="font-style")
ET.SubElement(Front, "CssParameter", name="font-size")
ET.SubElement(Front, "CssParameter", name="font-weight")
ET.SubElement(Fill, "CssParameter", name="fill")

Output = ET.ElementTree(StyledLayerDescriptor)
Output.write("SLD_Test.xml", xml_declaration=True, encoding='UTF-8')

parser = etree.XMLParser(remove_blank_text=True)
tree = etree.parse("SLD_Test.xml", parser)

tree.write("SLD_Test.xml", pretty_print=True)

Этот код работает для создания дерева печати xml

Я не просто хочу изменить пространства имен, но и переформатировать структуру xml, например, версия 1.0 не распознает, но некоторые данные необходимы в .

Я не ищу полных решений, поскольку пытаюсь разобраться как с Python, так и с XML. Любая помощь будет здорово! Даже ссылки на полезные уроки


person Bradley_Burrell    schedule 24.08.2017    source источник
comment
Возможный дубликат Удалить пространство имен и префикс из xml в python, используя lxml   -  person stovfl    schedule 24.08.2017
comment
Это выглядит похоже, но мне нужно реструктурировать (если это правильный термин) xml и скопировать информацию из одного в новый файл. Но это, безусловно, выглядит полезным, спасибо!   -  person Bradley_Burrell    schedule 24.08.2017


Ответы (1)


Из того, что я понял из вопроса, задача включает в себя внесение следующих изменений:

  • Сопоставьте элементы http://www.opengis.net/se с http://www.opengis.net/sld с тем же локальным именем
  • Измените элемент CssParameter на SvgParameter, сохранив атрибуты
  • Удалить xmlns:gml="http://www.opengis.net/gml"
  • Перевести ISO-8859-1 в UTF-8

В вашем вопросе пропущено несколько слов, поэтому я не совсем понимаю все правила. В любом случае вам следует внимательно изучить различия между SLD 1.1 и 1.0, чтобы убедиться, что у вас есть правила для этих различий. Не забывайте, вы можете немного схитрить, не написав правила для различий, которые не используются вашими входными файлами.

Вот короткая программа на Python (sld11-10.py), которая считывает каждый файл XML из входного каталога, затем создает выходной каталог и записывает идентичную структуру каталогов с теми же именами файлов в тех же каталогах, но с преобразованным содержимым, как описано.

#!/usr/bin/env python3
from lxml import etree
import os
import sys

sld10 = etree.XMLSchema(
    etree.parse("http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"))
sld11 = etree.XMLSchema(
    etree.parse("http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd"))
transform = etree.XSLT(etree.parse("sld11-10.xsl"))

def walk(sour_dir: str, dest_dir: str) -> None:
    os.mkdir(dest_dir)
    for item in os.listdir(sour_dir):
        sour_path = os.path.join(sour_dir, item)
        dest_path = os.path.join(dest_dir, item)
        if os.path.isdir(sour_path):
            walk(sour_path, dest_path)
        else:
            sour_doc = etree.parse(sour_path)
            if not sld11.validate(sour_doc):
                print(sour_path, sld11.error_log.last_error)
            dest_doc = transform(sour_doc)
            if not sld10.validate(dest_doc):
                print(dest_path, sld10.error_log.last_error)
            dest_doc.write(dest_path,
                pretty_print=True, xml_declaration=True, encoding="UTF-8")
    return None

if __name__ == "__main__":
    walk(sys.argv[1], sys.argv[2])

Вот указанный файл XSLT sld11-10.xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
  xmlns:se="http://www.opengis.net/se"
  xmlns:ogc="http://www.opengis.net/ogc" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:sld="http://www.opengis.net/sld"
  exclude-result-prefixes="sld se">

  <xsl:output encoding="UTF-8"/>

  <!--
    Chanage the version and the schemaLocation values
  -->

  <xsl:template match="/sld:StyledLayerDescriptor">
    <StyledLayerDescriptor xmlns="http://www.opengis.net/sld"
       xmlns:ogc="http://www.opengis.net/ogc"
       xmlns:xlink="http://www.w3.org/1999/xlink"
       xmlns:gml="http://www.opengis.net/gml">
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="version">1.0.0</xsl:attribute>
      <xsl:attribute name="xsi:schemaLocation"
        namespace="http://www.w3.org/2001/XMLSchema-instance">
        <xsl:text>http://www.opengis.net/sld </xsl:text>
        <xsl:text>http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd</xsl:text>
      </xsl:attribute>
      <xsl:apply-templates/>
    </StyledLayerDescriptor>
  </xsl:template>

  <!--
    Map SvgParameter elements in the http://www.opengis.net/se namespace
    to CssParameter in the http://www.opengis.net/sld namespace
  -->

  <xsl:template match="se:SvgParameter">
    <xsl:element name="CssParameter" namespace="http://www.opengis.net/sld">
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

  <!--
    Map remaining http://www.opengis.net/se elements and attributes
    to the http://www.opengis.net/sld namespace
  -->

  <xsl:template match="se:*">
    <xsl:element name="{local-name()}" namespace="http://www.opengis.net/sld">
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

  <!--
   Preserve all other elements and attributes
  -->

  <xsl:template match="*|@*">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!--
   Preserve processing instructuions and comments
  -->

  <xsl:template match="processing-instruction()|comment()">
    <xsl:copy>.</xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Часть if name == "main": walk(sys.argv[1], sys.argv[2] означает, что когда вы запускаете программу из командной строки, она будет использовать первые два параметра командной строки в качестве входных данных для процедуры обхода. Например, скажем, у вас есть sld11-10.py, sld11-10.xsl и input_directory на рабочем столе, а затем скажите, что input_directory содержит такие файлы, как этот

input_directory
  file1.xml
  file2.xml
  subdirectory
    file3.xml

затем, если у вас нет каталога с именем output_directory, вы можете запустить файл следующим образом

sld11-10.py input_directory output_directory

Программа создаст output_direcory со следующей структурой:

output_directory
  file1.xml
  file2.xml
  subdirectory
    file3.xml

Разница между input_directory и output_directory заключается в том, что XML-файлы в output_directory уже прошли XSLT-преобразование. Также обратите внимание, что во время преобразования информация о достоверности файлов XML, как SLD 1.0, так и SLD 1.1, будет записана на экран во время процесса.

person rcrews    schedule 25.08.2017
comment
Привет! Спасибо, я думаю, это может быть решением. Я просто пытаюсь разобраться, как это работает. Я думаю, что у меня это получилось лучше всего, кроме этого раздела. если name == main: walk(sys.argv[1], sys.argv[2]) - person Bradley_Burrell; 30.08.2017
comment
Обновлен ответ, чтобы добавить объяснение части if __name__ == "__main__". - person rcrews; 01.10.2017