将文件名放在标签<fileName> </fileName>之间的文件中

时间:2019-10-09 10:47:38

标签: python xml sed tags filenames

将几千个TIFF图像OCR转换为ALTO XML之后,我发现xml中的文件名标记为空。 xml文件开头为:

<?xml version="1.0" encoding="UTF-8"?>
<alto xmlns="http://www.loc.gov/standards/alto/ns-v3#" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/standards/alto/ns-v3# http://www.loc.gov/alto/v3/alto-3-0.xsd">
     <Description>
         <MeasurementUnit>pixel</MeasurementUnit>
             <sourceImageInformation>
                  <fileName>                      </fileName>
             </sourceImageInformation>

我想(递归)处理所有xml文件,并在标签之间添加tiff的名称。 xml的基本名称与tiff相同。 最好的方法是什么?我应该将bash与find和sed一起使用,还是将Python与string.replace一起使用,还是有更好的选择?

1 个答案:

答案 0 :(得分:4)

不要不要使用字符串处理工具来处理XML! XML不是常规格式,使用str.replace()sed或任何此类工具很可能会导致误报和错误。

使用XML解析器; Python具有xml.etree.ElementTree,这使此任务足够简单:

from pathlib import Path
from xml.etree import ElementTree as ET

for xmlfile in Path("directory_with_xml_files").glob("*.xml"):
    tree = ET.parse(xmlfile)
    namespace = tree.getroot().tag.partition('}')[0][1:]
    elem = tree.find(f".//a:fileName", {'a': namespace})
    elem.text = f"{xmlfile.stem}.tiff"
    tree.write(xmlfile, default_namespace=namespace,
               encoding="UTF-8", xml_declaration=True)

以上处理给定目录中的所有XML文件(使用pathlib module,使用Path.glob() method查找XML文件)。对于每个文件,它将XML数据解析为XML树,并使用该元素的简单XPath expressionupdates the text(使用{{3})在树中找到第一个<fileName>元素},它是没有扩展名.xml的基本名称),并将XML树写回到原始文件中。

您说过您使用filename stem,后者使用ALTO schema来区分版本。上面的代码应该从根元素中选择要使用的正确名称空间,然后在XPath查询中使用该名称空间(以a作为前缀)。

演示:

$ mkdir demo
$ cat << EOF > demo/foo.xml
> <?xml version="1.0" encoding="UTF-8"?>
> <alto xmlns="http://www.loc.gov/standards/alto/ns-v3#" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/standards/alto/ns-v3# http://www.loc.gov/alto/v3/alto-3-0.xsd">
>   <Description>
>     <MeasurementUnit>pixel</MeasurementUnit>
>     <sourceImageInformation>
>       <fileName>                      </fileName>
>     </sourceImageInformation>
>   </Description>
> </alto>
> EOF
$ cp demo/foo.xml demo/bar.xml
$ cp demo/foo.xml demo/baz.xml
$ python3.7
Python 3.7.4 (default, Jul  9 2019, 19:45:08)
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> from xml.etree import ElementTree as ET
>>> for xmlfile in Path("demo").glob("*.xml"):
...     tree = ET.parse(xmlfile)
...     namespace = tree.getroot().tag.partition('}')[0][1:]
...     elem = tree.find(f".//a:fileName", {'a': namespace})
...     elem.text = f"{xmlfile.stem}.tiff"
...     tree.write(xmlfile, default_namespace=namespace,
...                encoding="UTF-8", xml_declaration=True)
...
>>> ^D
$ cat demo/*.xml
<?xml version='1.0' encoding='UTF-8'?>
<alto xmlns="http://www.loc.gov/standards/alto/ns-v3#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/standards/alto/ns-v3# http://www.loc.gov/alto/v3/alto-3-0.xsd">
  <Description>
    <MeasurementUnit>pixel</MeasurementUnit>
    <sourceImageInformation>
      <fileName>bar.tiff</fileName>
    </sourceImageInformation>
  </Description>
</alto><?xml version='1.0' encoding='UTF-8'?>
<alto xmlns="http://www.loc.gov/standards/alto/ns-v3#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/standards/alto/ns-v3# http://www.loc.gov/alto/v3/alto-3-0.xsd">
  <Description>
    <MeasurementUnit>pixel</MeasurementUnit>
    <sourceImageInformation>
      <fileName>baz.tiff</fileName>
    </sourceImageInformation>
  </Description>
</alto><?xml version='1.0' encoding='UTF-8'?>
<alto xmlns="http://www.loc.gov/standards/alto/ns-v3#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/standards/alto/ns-v3# http://www.loc.gov/alto/v3/alto-3-0.xsd">
  <Description>
    <MeasurementUnit>pixel</MeasurementUnit>
    <sourceImageInformation>
      <fileName>foo.tiff</fileName>
    </sourceImageInformation>
  </Description>
</alto>