【问题标题】:Modifying an XML File - Dividing values修改 XML 文件 - 除值
【发布时间】:2017-09-12 13:07:47
【问题描述】:

我希望通过分割它们来修改 xml 文件中的值。

我需要将 se:SvgParameter[name="stroke-width"]se:Size 的值除以 3.6。我在 Python.org,Modifying an XML File 上找到了这个教程,但它似乎不起作用,我在这里找不到类似的东西。任何帮助或意见将不胜感激!

这是一些示例 XML,但我希望能够将脚本输出到包含多个文件的文件夹中,并让它转换所有文件。

XML:

<?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>QGIS_SLD_ScaleProblem</se:Name>
    <se:Description>
      <se:Title>QGIS_SLD_ScaleProblem</se:Title>
      <se:Abstract>This SLD is in Pixels, but QGIS will read it as mm</se:Abstract>
    </se:Description>
    <UserStyle>
      <se:Name>QGIS_SLD_ScaleProblem</se:Name>
      <se:FeatureTypeStyle>
        <se:Rule>
          <se:Name>QGIS_SLD_ScaleProblem_Line</se:Name>
          <se:LineSymbolizer>
            <se:Name>Line</se:Name>
            <se:Stroke>
              <se:SvgParameter name="stroke">#FF0000</se:SvgParameter>
              <se:SvgParameter name="stroke-width">36</se:SvgParameter>
            </se:Stroke>
          </se:LineSymbolizer>
        </se:Rule>
        <se:Rule>
          <se:Name>QGIS_SLD_ScaleProblem_Point</se:Name>
          <se:PointSymbolizer>
            <se:Name>Point</se:Name>
            <se:Graphic>
             <se:Mark>
              <se:WellKnownName>circle</se:WellKnownName>
              <se:Fill>
               <se:SvgParameter name="fill">#FF0000</se:SvgParameter>
              </se:Fill>
             </se:Mark>
             <se:Size>36</se:Size>
            </se:Graphic>
          </se:PointSymbolizer>
        </se:Rule>
      </se:FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>

代码:

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

tree = ET.parse('QGIS-SLD-ScaleProblem_Line.sld')
root = tree.getroot()

# To check that the script is reading the correct file
print("SLD file", root[0][0].text, "loaded.")

# Registers namespaces to prevent them being filled with defaults
ET.register_namespace('', "http://www.opengis.net/sld")
ET.register_namespace('ogc', "http://www.opengis.net/ogc")
ET.register_namespace('xsi', "http://www.w3.org/2001/XMLSchema-instance")
ET.register_namespace('xlink', "http://www.w3.org/1999/xlink")
ET.register_namespace('schemaLocation', "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd")
ET.register_namespace('se', "http://www.opengis.net/se")

# This section "should" search the XML for se:SvgParameter name="stroke-width" and se:Size and divide the value by 3.6
for SvgParameter in root.iter('SvgParameter'):
    new_SvgParameter = int(SvgParameter.text) / 3.6
    SvgParameter.text = str(new_SvgParameter)
for Size in root.iter('Size'):
    new_Size= int(Size.text) / 3.6
    Size.text = str(new_Size)

tree.write("GIS-SLD-ScaleFixed.sld", xml_declaration=True, encoding='ISO-8859-1')

我看过的答案:

【问题讨论】:

    标签: python xml lxml sld


    【解决方案1】:

    考虑XSLT 设计用于转换XML 文件的专用语言。并且 Python 的 lxml 模块可以运行 XSLT 1.0 脚本。此外,XSLT 可以在 Python 之外运行,因此具有可移植性。

    只需调用identity transform 即可按原样复制整个文档,然后在选定节点上运行除法。这种方法不需要for 循环或if 逻辑。

    XSLT (另存为 .xsl 文件,一种特殊的格式良好的 XML 文件)

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                                  xmlns:se="http://www.opengis.net/se">                               
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="se:SvgParameter[@name='stroke-width']|se:Size">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:value-of select="format-number(text(), '#') div 3.6"/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    Python (在下面的进程循环中迭代多个文件)

    import lxml.etree as et
    
    # LOAD XML AND XSL
    doc = et.parse('Input.xml')
    xsl = et.parse('XSLTScript.xsl')
    
    # TRANSFORM
    transform = et.XSLT(xsl)
    result = transform(doc)
    
    # OUTPUT TO SCREEN    
    print(result)
    
    # OUTPUT TO FILE
    with open('Output.xml', 'wb') as f:
        f.write(result)
    

    输出

    <?xml version="1.0"?>
    <StyledLayerDescriptor 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" xmlns:se="http://www.opengis.net/se" version="1.1.0" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd">
      <NamedLayer>
        <se:Name>QGIS_SLD_ScaleProblem</se:Name>
        <se:Description>
          <se:Title>QGIS_SLD_ScaleProblem</se:Title>
          <se:Abstract>This SLD is in Pixels, but QGIS will read it as mm</se:Abstract>
        </se:Description>
        <UserStyle>
          <se:Name>QGIS_SLD_ScaleProblem</se:Name>
          <se:FeatureTypeStyle>
            <se:Rule>
              <se:Name>QGIS_SLD_ScaleProblem_Line</se:Name>
              <se:LineSymbolizer>
                <se:Name>Line</se:Name>
                <se:Stroke>
                  <se:SvgParameter name="stroke">#FF0000</se:SvgParameter>
                  <se:SvgParameter name="stroke-width">10</se:SvgParameter>
                </se:Stroke>
              </se:LineSymbolizer>
            </se:Rule>
            <se:Rule>
              <se:Name>QGIS_SLD_ScaleProblem_Point</se:Name>
              <se:PointSymbolizer>
                <se:Name>Point</se:Name>
                <se:Graphic>
                  <se:Mark>
                    <se:WellKnownName>circle</se:WellKnownName>
                    <se:Fill>
                      <se:SvgParameter name="fill">#FF0000</se:SvgParameter>
                    </se:Fill>
                  </se:Mark>
                  <se:Size>10</se:Size>
                </se:Graphic>
              </se:PointSymbolizer>
            </se:Rule>
          </se:FeatureTypeStyle>
        </UserStyle>
      </NamedLayer>
    </StyledLayerDescriptor>
    

    【讨论】:

    • 谢谢!这正是我所追求的!我想我需要更多地了解 XSLT!
    猜你喜欢
    • 2021-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    相关资源
    最近更新 更多