有没有一种方法可以在使用python脚本操作XML时保留XML中属性字符串中的换行符?

8yoxcaq7  于 2023-06-04  发布在  Python
关注(0)|答案(1)|浏览(161)

根据(例如)this discussion,XML文件中的字符串中的换行符是允许的。我有这样一个文件,我需要操纵它。具体地说,从具有现有id的某些子元素中,我需要创建具有新id的副本。我有一个测试Python脚本来做这件事:

import xml.etree.ElementTree as ET
from xml.dom import minidom
import copy

def double_override_entries(input_file, search_id, replace_id, output_file):
    tree = ET.parse(input_file)
    root = tree.getroot()

    for override_elem in root.findall(".//override"):
        for language_elem in override_elem.findall(".//language[@id='{}']".format(search_id)):
            language_elem_copy = copy.deepcopy(language_elem)
            language_elem_copy.set('id', replace_id)
            override_elem.append( language_elem_copy)

    xml_str = ET.tostring(root, encoding='utf-8').decode('utf-8')

    with open(output_file, 'w', encoding='utf-8') as file:
        file.write(xml_str)

input_file = "input.xml"
search_id = "yy"
replace_id = "zz"
output_file = "output.xml"

double_override_entries(input_file, search_id, replace_id, output_file)

这是可行的,除了一件事:原始XML中字符串内的换行符已被删除。我正在寻找一种方法来做同样的操作,但在属性值字符串中保留这些换行符。
输入:

<?xml version="1.0" encoding="UTF-8"?>
<model>
  <overrides>
    <override identifier="id-12391" labelPlacement="manual" labelOffset="(35,20)">
      <language id="en" labelText="Internal
        Exploitation
        Dependencies"/>
      <language id="yy" labelText="Internal
        Exploitation
        Dependencies"/>
    </override>
  </overrides>
</model>

输出:

<model>
  <overrides>
    <override identifier="id-12391" labelPlacement="manual" labelOffset="(35,20)">
      <language id="en" labelText="Internal         Exploitation         Dependencies" />
      <language id="yy" labelText="Internal         Exploitation         Dependencies" />
    <language id="zz" labelText="Internal         Exploitation         Dependencies" />
    </override>
  </overrides>
</model>

[更新] ElementTree是兼容的(见下面的答案),所以从问题中删除了该语句。不过,我仍然希望有一个python解决方案来解决这种不兼容的使用。[/更新]
任何技巧都可以,尽管我需要在macOS + MacPorts上运行它(目前使用python3.11)

2sbarzqh

2sbarzqh1#

我找到了this SO question and answer,它假定属性中的换行符应该从输入传递到输出。最受欢迎的答案是XML规范的这一部分:
5.2角色逃脱
XML 1.0规范要求XML处理器对XML文档中的空白字符执行某些简单的转换,无论这些字符是用作行分隔符还是出现在属性值中。对于变换结果中的每个字符,将存在由信息集描述的字符信息项。[...]

但这只是部分适用于这种情况,因为深入研究这个主题,你会发现关于 * 属性值规范化 * 的章节,其中指出:
3.3.3属性值归一化

在将属性值传递给应用程序或检查其有效性之前,XML处理器MUST通过应用下面的算法或使用其他方法将属性值规范化,以使传递给应用程序的值与算法产生的值相同。

该算法为:

1.所有的换行符必须在输入到#xA时进行规范化,如2.11行尾处理中所述,因此该算法的其余部分以这种方式对规范化的文本进行操作。
1.从由空字符串组成的规范化值开始。

  • 对于未规范化属性值中的每个字符、实体引用或字符引用,从第一个字符开始,一直到最后一个字符,执行以下操作:
  • 对于字符引用,将引用的字符追加到规范化值。
  • 对于实体引用,递归地将此算法的步骤3应用于实体的替换文本。
  • 对于白色字符(#x20,#xD,#xA,#x9),将空格字符(#x20)附加到规范化值。
  • 对于另一个字符,将该字符追加到规范化值。

如果属性类型不是CDATA,那么XML处理器必须通过丢弃任何前导和尾随空格(#x20)字符,并通过用单个空格(#x20)字符替换空格(#x20)字符序列来进一步处理规范化的属性值。
注意,如果未规范化的属性值包含对除空格(#x20)之外的白色字符的字符引用,则规范化的值包含所引用的字符本身(#xD、#xA或#x9)。这与未规范化的值包含白色字符(不是引用)的情况形成对比,该空白字符在规范化的值中被空白字符(#x20)替换,并且还与未规范化的值包含实体引用的情况形成对比,该实体引用的替换文本包含空白字符;在递归处理中,在归一化值中用空格字符(#x20)替换空白字符。
我用xsltprocidentity template 测试了你的输入,结果和你的一样。因此,它似乎符合标准。
应用上述规范中的算法,输出符合预期。为了可比性,在步骤3.3中应用将每个#xA变换为#x20的归一化算法。
所以你问题的答案显然是:不要啊!
解决方案:将包含换行符的值放在元素中,而不是属性中。

相关问题