import lxml.etree as etree
# 追加・更新関数
class PathManipulator:
@staticmethod
def custom_split(xpath, sep='/'):
result = []
in_quotes = False
start = 0
for i, char in enumerate(xpath):
if char in ('"', "'"):
in_quotes = not in_quotes
elif char in sep and not in_quotes:
result.append(xpath[start:i])
start = i + 1
result.append(xpath[start:])
return [x for x in result if x] # 空文字列を除外する
@staticmethod
def strncmp(s1, s2, n):
len1 = len(s1)
len2 = len(s2)
min_len = min(len1, len2, n)
for i in range(min_len):
if s1[i] != s2[i]:
return ord(s1[i]) - ord(s2[i])
if min_len < n:
return len1 - len2
else:
return 0
@staticmethod
def split_except_literal(input_string, separator):
result = []
temp = ""
skip_count = 0
separetor_len = len(separator)
literal_started = False
for i, char in enumerate(input_string):
separator_candidate = PathManipulator.extract_string(
input_string, i, separetor_len)
if skip_count > 0:
skip_count -= 1
continue
if char == "'":
literal_started = not literal_started
temp += char
elif PathManipulator.strncmp(separator_candidate, separator, separetor_len) == 0 and not literal_started:
skip_count = separetor_len - 1
result.append(temp)
temp = ""
else:
temp += char
if temp:
result.append(temp)
return result
@staticmethod
def extract_string(string, start_index, length):
return string[start_index:start_index + length]
# 追加・更新関数
class XmlManipulator:
def __init__(self, filepath):
self.filepath = filepath
self. parser = etree.XMLParser(remove_blank_text=True)
self.tree = etree.parse(self.filepath, self.parser)
self.root = self.tree.getroot()
def upsert(self, xpath):
parts = PathManipulator.custom_split(xpath)
current_element = self.root
query = "."
for i, part in enumerate(parts):
if (part == "."):
continue
# タグ名と属性([]をひとかたまりの文字列として扱う)取得する
tag_name, *attributes_string = PathManipulator.custom_split(part, '[]')
print(attributes_string)
print(part + " -> " + tag_name + " -> " + str(attributes_string))
tag_name = tag_name.strip()
attributes_string_internal = " ".join(attributes_string).strip()
attributes_string = ""
if len(attributes_string_internal) is not 0:
attributes_string = '[' + attributes_string_internal + ']'
query = f"./{tag_name}{attributes_string}"
elements = current_element.xpath(query)
if not elements:
# 要素が存在しない場合は新規作成する
new_element = etree.SubElement(current_element, tag_name)
# 属性を設定する
for attribute in PathManipulator.split_except_literal(attributes_string_internal, 'and'):
attribute = attribute.strip()
key, value = attribute.split('=')
key = key.strip("@")
new_element.set(key.strip(), value.strip("]['\""))
current_element = new_element
else:
# 要素が存在する場合はその要素を選択する
print("Found: " + str(len(elements)) +
" elements for the given XPath = " + query)
current_element = elements[0]
return current_element
# 削除関数
def delete(self, xpath):
elements = self.root.xpath(xpath)
if len(elements) > 1:
print("Warning: Multiple elements found for the given XPath = " + xpath)
elif len(elements) == 1:
parent = elements[0].getparent()
parent.remove(elements[0])
else:
print("Warning: No elements found for the given XPath = " + xpath)
def save(self, filepath):
# 名前空間を削除して保存する
for elem in self.root.iter():
elem.tag = etree.QName(elem).localname
# インデントを行う
tree = self.root.getroottree()
tree.write(filepath, pretty_print=True,
encoding='utf-8', xml_declaration=True)
# テスト用のコード
if __name__ == "__main__":
xml_mod =XmlManipulator('input.xml')
# 追加・更新のテスト
# ない場合は新規作成
xml_mod.upsert(
"./base[@class='hogeC' and @distName='/aaa/bbb-99/fff-2/ddd-1/']")
# ない場合は新規作成
xml_mod.upsert(
"./base[@class='hogeC' and @distName='/aaa/bbb-99/fff-2/ddd-4/']")
# ない場合は新規作成
xml_mod.upsert(
"./base[@class='hogeC' and @distName='/aaa/eee-99/fff-2/ddd-4/']")
element = xml_mod.upsert(
"./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
element.text = "hoge1"
element = xml_mod.upsert(
"./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
element.text = "hoge2"
element = xml_mod.upsert(
"./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
element.text = "hoge3"
element = xml_mod.upsert(
"./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
element.text = "hoge4"
element = xml_mod.upsert(
"./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
element.text = "hoge5"
xml_mod.upsert("./base[@class='hogeA']") # ある場合は取得
# 削除のテスト
xml_mod.delete("./base[@class='hogeC']") # 削除する場合
xml_mod.delete("./base[@class='hogeD']") # 存在しない場合
# 保存のテスト
xml_mod.save( "output.xml")
import csv
import os
class CSVFileManager:
def __init__(self, file_path, title_row_index=0, primary_keys=None):
self.file_path = file_path
self.title_row_index = title_row_index
self.primary_keys = primary_keys or []
self.data = self._read_csv()
def _read_csv(self):
with open(self.file_path, 'r', newline='') as file:
reader = csv.reader(file)
data = list(reader)
return data
def save(self, file_path=None):
file_path = file_path or self.file_path
with open(file_path, 'w', newline='') as file:
writer = csv.writer(file)
writer.writerows(self.data)
def upsert(self, new_row):
title_row = self.data[self.title_row_index]
# Check if primary keys are provided
if not self.primary_keys:
raise ValueError("Primary keys not specified.")
# Find index of primary key columns
key_indices = [title_row.index(key) for key in self.primary_keys]
# Check for duplicate primary keys
for row in self.data[self.title_row_index + 1:]:
if all(row[idx] == new_row[title_row.index(title)] for idx, title in zip(key_indices, self.primary_keys)):
raise ValueError("Duplicate primary keys found.")
# Upsert or append the new row
for idx, row in enumerate(self.data[self.title_row_index + 1:], start=self.title_row_index + 1):
if all(row[idx] == new_row[title_row.index(title)] for idx, title in zip(key_indices, self.primary_keys)):
self.data[idx] = new_row
break
else:
self.data.append(new_row)
def delete(self, key_values):
title_row = self.data[self.title_row_index]
# Check if primary keys are provided
if not self.primary_keys:
raise ValueError("Primary keys not specified.")
# Find index of primary key columns
key_indices = [title_row.index(key) for key in self.primary_keys]
# Find rows with matching primary keys
matching_rows = []
for idx, row in enumerate(self.data[self.title_row_index + 1:], start=self.title_row_index + 1):
if all(row[idx] == value for idx, value in zip(key_indices, key_values)):
matching_rows.append(idx)
# Error if no matching rows found
if not matching_rows:
print("Warning: No rows found with specified primary keys.")
return
# Error if multiple matching rows found
if len(matching_rows) > 1:
raise ValueError("Multiple rows found with specified primary keys.")
# Delete matching row
del self.data[matching_rows[0]]
# Example usage:
file_path = "example.csv"
primary_keys = ["ID"]
# Initialize CSVFileManager instance
manager = CSVFileManager(file_path, title_row_index=3, primary_keys=primary_keys)
# Upsert a new row
new_row = ["123", "John Doe", "30"]
manager.upsert(new_row)
# Delete a row
manager.delete(["123"])
# Save changes to file
manager.save()
import pandas as pd
import csv
def custom_split(csv_line, sep=',', strip=True):
result = []
in_quotes = False
start = 0
for i, char in enumerate(csv_line):
if char in ('"', "'"):
in_quotes = not in_quotes
elif char in sep and not in_quotes:
csv_value = csv_line[start:i]
if strip:
csv_value = csv_value.strip()
csv_value = remove_outer_quotes(csv_value)
result.append(csv_value)
start = i + 1
csv_value = csv_line[start:]
if strip:
csv_value = csv_value.strip()
result.append(csv_value)
return [x for x in result if x] # 空文字列を除外する
def remove_outer_quotes(s):
if len(s) < 2 or (s[0] != s[-1]) or (s[0] not in ['"', "'"]):
return s
elif s.count(s[0]) >= 3:
return s
else:
return s[1:-1]
class CustomCSVParser:
def __init__(self, file_path, skiprows=3):
self.data = []
with open(file_path, 'r') as f:
lines = f.readlines()
self.titles = custom_split(lines[skiprows].strip())
data_lines = lines[skiprows + 1:]
for line in data_lines:
line = line.strip()
if line:
row = custom_split(line)
self.data.append(row)
def convertToCsv(self, dn, list_val, param_name, value):
try:
dn_index = self.titles.index('DN')
list_index = self.titles.index('list')
param_index = self.titles.index('param abbreviated name')
value_index = self.titles.index('value')
for row in self.data:
row_list = row[list_index]
print(len(row_list), len(list_val), len("''"))
if row_list == list_val:
print("same!")
if row[dn_index] == dn and row_list == list_val and row[param_index] == param_name:
values = row[value_index].split(',')
for val_pair in values:
key, val = val_pair.split(':')
if key == value:
return val
raise ValueError("Specified value not found in CSV.")
raise ValueError("Specified combination not found in CSV.")
except Exception as e:
return str(e)
def convertToCom(self, dn, list_val, param_name, value):
try:
row = self.data[(self.data['DN'] == dn) & (self.data['list'] == list_val) & (
self.data['param abbreviated name'] == param_name)]
if not row.empty:
if value in row.values[0][4:]:
idx = row.values[0][4:].tolist().index(value) + 1
return row.columns[idx]
else:
raise ValueError("Specified value not found in CSV.")
else:
raise ValueError("Specified combination not found in CSV.")
except Exception as e:
return str(e)
# Example usage:
converter = CustomCSVParser("stepdata.csv")
print(converter.convertToCsv("/aaa/bbb-/ccc-/ddd-",
'', "data_name_1", "111")) # Output: h2
print(converter.convertToCom("/aaa/bbb-/ccc-/ddd-",
'', "data_name_1", "h2")) # Output: 112