Получение родительского атрибута Excel xml с помощью python lxml

У меня есть файл Excel XML, в котором мне нужно получить идентификатор стиля элементов, в которых есть ячейка определенного цвета (интерьер).

У меня есть этот Excel XML, как пример:

И это заголовок документа:

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:o="urn:schemas-microsoft-com:office:office"
  xmlns:x="urn:schemas-microsoft-com:office:excel"
  xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:html="http://www.w3.org/TR/REC-html40">
  <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">

И вот что мне нужно для доступа:

<Style ss:ID="s64">
   <Interior ss:Color="#00CC00" ss:Pattern="Solid"/>
</Style>

Мне нужно написать функцию, передавая цвет #00CC00, я получаю этот элемент, а затем я могу получить доступ к его родителю, чтобы получить идентификатор.

Я пытался с этим кодом, и он не действителен. Я думаю, что я должен использовать пространства имен.

parser = et.parse(str(file))
color = parser.xpath("//interior[@ss:Color='#FFCC00'")
par = color.getparent()
print(par)

Мне нужно, чтобы код возвращал "s64".

Однако это не правильный код. Чего мне не хватает?

РЕДАКТИРОВАТЬ: Я хочу отредактировать свой вопрос и добавить дополнительную информацию, после поиска дополнительной информации, я написал этот кусок кода

def _find_color(self):
    """
    Find the color in the xml file and returns the attribute.
    """
    print('The folder is: ', self.path)
    nsd ={'Default':'urn:schemas-microsoft-com:office:spreadsheet',
                'o': 'urn:schemas-microsoft-com:office:office', 
                'ss': 'urn:schemas-microsoft-com:office:spreadsheet'}
    if pathlib.Path(self.path).exists():
        for file in self.folder.glob('**/*.xml'):
            print('The file is ', file)
            parser = et.parse(str(file))
            color = parser.xpath("//style/interior[@ss:Color='#00CC00']",namespaces=nsd)
            print(color)
            #par = color.getparent()
            #print(par)

Однако он возвращает пустой список. Так что ничего не находит.

Добавление всей исходной части, с которой мне интересно работать

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:o="urn:schemas-microsoft-com:office:office"
  xmlns:x="urn:schemas-microsoft-com:office:excel"
  xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:html="http://www.w3.org/TR/REC-html40">
  <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
     <Author>Somebody</Author>
     <LastAuthor>Somebody</LastAuthor>
     <Created>2016-05-16T10:44:52Z</Created>
     <Company>SomeCompany</Company>
     <Version>12.00</Version>
  </DocumentProperties>
  <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
     <WindowHeight>9495</WindowHeight>
     <WindowWidth>20835</WindowWidth>
     <WindowTopX>240</WindowTopX>
     <WindowTopY>420</WindowTopY>
     <ProtectStructure>False</ProtectStructure>
     <ProtectWindows>False</ProtectWindows>
  </ExcelWorkbook>
  <Styles>
    <Style ss:ID="Default" ss:Name="Normal">
      <Alignment ss:Vertical="Bottom"/>
      <Borders/>
      <Font ss:FontName="Arial" x:Family="Swiss"/>
      <Interior/>
      <NumberFormat/>
      <Protection/>
    </Style>
    <Style ss:ID="s63">
      <Font ss:FontName="Arial" x:Family="Swiss" ss:Color="#FF0000" ss:Bold="1"/>
    </Style>
    <Style ss:ID="s64">
      <Interior ss:Color="#00CC00" ss:Pattern="Solid"/>
    </Style>
    <Style ss:ID="s65">
       <Font ss:FontName="Arial" x:Family="Swiss" ss:Color="#FF0000" ss:Bold="1"/>
     <Interior ss:Color="#44CF00" ss:Pattern="Solid"/>
      </Style>
   </Styles>

Я не могу найти элемент, основанный на атрибуте, используя xpath.

2 ответа

Решение

Вот как это можно сделать.

from lxml import etree as ET

NS = {"ss": "urn:schemas-microsoft-com:office:spreadsheet"}

tree = ET.parse("workbook.xml")
interior = tree.find("//ss:Style/ss:Interior[@ss:Color='#00CC00']", namespaces=NS)
print(interior.getparent().get("{urn:schemas-microsoft-com:office:spreadsheet}ID"))

Выход:

s64

Комментарии:

  • ss Префикс должен использоваться на всех элементах.
  • XML чувствителен к регистру (Style знак равно style).
  • При получении значения пространства имен ID атрибут, URI (не префикс), должен использоваться.

После поиска я наконец-то нашел решение. Похоже, что одной из ошибок было то, что я не генерировал дерево (я решил это с помощью getroot()). Поэтому мое решение:

def _find_color(self):
    """
    Find the color in the xml file and returns the attribute.
    """
    print('The folder is: ', self.path)
    nsd ={'Default':'urn:schemas-microsoft-com:office:spreadsheet',
                'o': 'urn:schemas-microsoft-com:office:office', 
                'ss': 'urn:schemas-microsoft-com:office:spreadsheet'}
    if pathlib.Path(self.path).exists():
        for file in self.folder.glob('**/*.xml'):
            print('The file is ', file)
            parser = et.parse(str(file))
            root=parser.getroot()
            color = root.xpath("//Default:Interior[@ss:Color='#FFCC00']",namespaces=nsd)
  print(color)
            for element in color:
                print('Tag: ', element.tag, 'Attribute: ', element.attrib)
                par_id= element.getparent().get("{urn:schemas-microsoft-com:office:spreadsheet}ID")
                print(par_id)

Возвращает с64.

Для получения идентификатора родителя я использовал решение, предоставленное мне mzjn. Поскольку я знал, что должен был использовать URI вместо короткого имени.

Другие вопросы по тегам