praisonaiagents 0.0.23__py3-none-any.whl → 0.0.24__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- praisonaiagents/tools/__init__.py +165 -2
- praisonaiagents/tools/arxiv_tools.py +292 -0
- praisonaiagents/tools/calculator_tools.py +278 -0
- praisonaiagents/tools/csv_tools.py +266 -0
- praisonaiagents/tools/duckdb_tools.py +268 -0
- praisonaiagents/tools/duckduckgo_tools.py +52 -0
- praisonaiagents/tools/excel_tools.py +310 -0
- praisonaiagents/tools/file_tools.py +274 -0
- praisonaiagents/tools/json_tools.py +515 -0
- praisonaiagents/tools/newspaper_tools.py +354 -0
- praisonaiagents/tools/pandas_tools.py +326 -0
- praisonaiagents/tools/python_tools.py +423 -0
- praisonaiagents/tools/shell_tools.py +278 -0
- praisonaiagents/tools/spider_tools.py +431 -0
- praisonaiagents/tools/test.py +56 -0
- praisonaiagents/tools/tools.py +5 -36
- praisonaiagents/tools/wikipedia_tools.py +272 -0
- praisonaiagents/tools/xml_tools.py +498 -0
- praisonaiagents/tools/yaml_tools.py +417 -0
- praisonaiagents/tools/yfinance_tools.py +213 -0
- {praisonaiagents-0.0.23.dist-info → praisonaiagents-0.0.24.dist-info}/METADATA +1 -1
- praisonaiagents-0.0.24.dist-info/RECORD +42 -0
- praisonaiagents-0.0.23.dist-info/RECORD +0 -24
- {praisonaiagents-0.0.23.dist-info → praisonaiagents-0.0.24.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.23.dist-info → praisonaiagents-0.0.24.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,498 @@
|
|
1
|
+
"""Tools for working with XML files.
|
2
|
+
|
3
|
+
Usage:
|
4
|
+
from praisonaiagents.tools import xml_tools
|
5
|
+
tree = xml_tools.read_xml("data.xml")
|
6
|
+
|
7
|
+
or
|
8
|
+
from praisonaiagents.tools import read_xml, write_xml, transform_xml
|
9
|
+
tree = read_xml("data.xml")
|
10
|
+
"""
|
11
|
+
|
12
|
+
import logging
|
13
|
+
from typing import List, Dict, Union, Optional, Any, Tuple
|
14
|
+
from importlib import util
|
15
|
+
import xml.etree.ElementTree as ET
|
16
|
+
import xml.dom.minidom as minidom
|
17
|
+
from io import StringIO
|
18
|
+
import json
|
19
|
+
|
20
|
+
class XMLTools:
|
21
|
+
"""Tools for working with XML files."""
|
22
|
+
|
23
|
+
def __init__(self):
|
24
|
+
"""Initialize XMLTools."""
|
25
|
+
pass
|
26
|
+
|
27
|
+
def read_xml(
|
28
|
+
self,
|
29
|
+
filepath: str,
|
30
|
+
encoding: str = 'utf-8',
|
31
|
+
validate_schema: Optional[str] = None,
|
32
|
+
parser: str = 'lxml'
|
33
|
+
) -> ET.Element:
|
34
|
+
"""Read an XML file with optional schema validation.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
filepath: Path to XML file
|
38
|
+
encoding: File encoding
|
39
|
+
validate_schema: Optional path to XSD schema file
|
40
|
+
parser: XML parser to use ('lxml' or 'etree')
|
41
|
+
|
42
|
+
Returns:
|
43
|
+
ElementTree root element
|
44
|
+
"""
|
45
|
+
try:
|
46
|
+
if parser == 'lxml':
|
47
|
+
if util.find_spec('lxml') is None:
|
48
|
+
error_msg = "lxml package is not available. Please install it using: pip install lxml"
|
49
|
+
logging.error(error_msg)
|
50
|
+
return None
|
51
|
+
import lxml.etree as lxml_etree
|
52
|
+
tree = lxml_etree.parse(filepath)
|
53
|
+
root = tree.getroot()
|
54
|
+
else:
|
55
|
+
tree = ET.parse(filepath)
|
56
|
+
root = tree.getroot()
|
57
|
+
|
58
|
+
if validate_schema:
|
59
|
+
if util.find_spec('xmlschema') is None:
|
60
|
+
error_msg = "xmlschema package is not available. Please install it using: pip install xmlschema"
|
61
|
+
logging.error(error_msg)
|
62
|
+
return None
|
63
|
+
import xmlschema
|
64
|
+
schema = xmlschema.XMLSchema(validate_schema)
|
65
|
+
if not schema.is_valid(filepath):
|
66
|
+
error_msg = f"XML file does not validate against schema: {schema.validate(filepath)}"
|
67
|
+
logging.error(error_msg)
|
68
|
+
return None
|
69
|
+
|
70
|
+
return root
|
71
|
+
|
72
|
+
except Exception as e:
|
73
|
+
error_msg = f"Error reading XML file {filepath}: {str(e)}"
|
74
|
+
logging.error(error_msg)
|
75
|
+
return None
|
76
|
+
|
77
|
+
def write_xml(
|
78
|
+
self,
|
79
|
+
root: ET.Element,
|
80
|
+
filepath: str,
|
81
|
+
encoding: str = 'utf-8',
|
82
|
+
pretty: bool = True,
|
83
|
+
xml_declaration: bool = True
|
84
|
+
) -> bool:
|
85
|
+
"""Write XML Element tree to file.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
root: XML Element tree root
|
89
|
+
filepath: Output file path
|
90
|
+
encoding: File encoding
|
91
|
+
pretty: Format output with proper indentation
|
92
|
+
xml_declaration: Include XML declaration
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
True if successful, False otherwise
|
96
|
+
"""
|
97
|
+
try:
|
98
|
+
# Convert to string
|
99
|
+
if pretty:
|
100
|
+
xml_str = minidom.parseString(
|
101
|
+
ET.tostring(root, encoding='unicode')
|
102
|
+
).toprettyxml(indent=' ')
|
103
|
+
else:
|
104
|
+
xml_str = ET.tostring(
|
105
|
+
root,
|
106
|
+
encoding='unicode'
|
107
|
+
)
|
108
|
+
|
109
|
+
# Add declaration if requested
|
110
|
+
if xml_declaration:
|
111
|
+
if not xml_str.startswith('<?xml'):
|
112
|
+
xml_str = (
|
113
|
+
f'<?xml version="1.0" encoding="{encoding}"?>\n'
|
114
|
+
+ xml_str
|
115
|
+
)
|
116
|
+
|
117
|
+
# Write to file
|
118
|
+
with open(filepath, 'w', encoding=encoding) as f:
|
119
|
+
f.write(xml_str)
|
120
|
+
|
121
|
+
return True
|
122
|
+
except Exception as e:
|
123
|
+
error_msg = f"Error writing XML file {filepath}: {str(e)}"
|
124
|
+
logging.error(error_msg)
|
125
|
+
return False
|
126
|
+
|
127
|
+
def transform_xml(
|
128
|
+
self,
|
129
|
+
xml_file: str,
|
130
|
+
xslt_file: str,
|
131
|
+
output_file: str,
|
132
|
+
params: Optional[Dict[str, str]] = None
|
133
|
+
) -> bool:
|
134
|
+
"""Transform XML using XSLT stylesheet.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
xml_file: Input XML file
|
138
|
+
xslt_file: XSLT stylesheet file
|
139
|
+
output_file: Output file path
|
140
|
+
params: Optional parameters for transformation
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
True if successful, False otherwise
|
144
|
+
"""
|
145
|
+
try:
|
146
|
+
# Parse XML and XSLT
|
147
|
+
if util.find_spec('lxml') is None:
|
148
|
+
error_msg = "lxml package is not available. Please install it using: pip install lxml"
|
149
|
+
logging.error(error_msg)
|
150
|
+
return False
|
151
|
+
import lxml.etree as lxml_etree
|
152
|
+
xml_doc = lxml_etree.parse(xml_file)
|
153
|
+
xslt_doc = lxml_etree.parse(xslt_file)
|
154
|
+
transform = lxml_etree.XSLT(xslt_doc)
|
155
|
+
|
156
|
+
# Apply transformation
|
157
|
+
if params:
|
158
|
+
result = transform(xml_doc, **params)
|
159
|
+
else:
|
160
|
+
result = transform(xml_doc)
|
161
|
+
|
162
|
+
# Write result
|
163
|
+
result.write(
|
164
|
+
output_file,
|
165
|
+
pretty_print=True,
|
166
|
+
xml_declaration=True,
|
167
|
+
encoding='utf-8'
|
168
|
+
)
|
169
|
+
|
170
|
+
return True
|
171
|
+
except Exception as e:
|
172
|
+
error_msg = f"Error transforming XML: {str(e)}"
|
173
|
+
logging.error(error_msg)
|
174
|
+
return False
|
175
|
+
|
176
|
+
def validate_xml(
|
177
|
+
self,
|
178
|
+
xml_file: str,
|
179
|
+
schema_file: str
|
180
|
+
) -> Tuple[bool, Optional[str]]:
|
181
|
+
"""Validate XML against XSD schema.
|
182
|
+
|
183
|
+
Args:
|
184
|
+
xml_file: XML file to validate
|
185
|
+
schema_file: XSD schema file
|
186
|
+
|
187
|
+
Returns:
|
188
|
+
Tuple of (is_valid, error_message)
|
189
|
+
"""
|
190
|
+
try:
|
191
|
+
if util.find_spec('xmlschema') is None:
|
192
|
+
error_msg = "xmlschema package is not available. Please install it using: pip install xmlschema"
|
193
|
+
logging.error(error_msg)
|
194
|
+
return False, error_msg
|
195
|
+
import xmlschema
|
196
|
+
schema = xmlschema.XMLSchema(schema_file)
|
197
|
+
schema.validate(xml_file)
|
198
|
+
return True, None
|
199
|
+
except xmlschema.validators.exceptions.XMLSchemaValidationError as e:
|
200
|
+
return False, str(e)
|
201
|
+
except Exception as e:
|
202
|
+
error_msg = f"Error validating XML: {str(e)}"
|
203
|
+
logging.error(error_msg)
|
204
|
+
return False, error_msg
|
205
|
+
|
206
|
+
def xml_to_dict(
|
207
|
+
self,
|
208
|
+
root: Union[str, ET.Element],
|
209
|
+
preserve_attrs: bool = True
|
210
|
+
) -> Dict[str, Any]:
|
211
|
+
"""Convert XML to dictionary.
|
212
|
+
|
213
|
+
Args:
|
214
|
+
root: XML string or Element tree root
|
215
|
+
preserve_attrs: Keep XML attributes in result
|
216
|
+
|
217
|
+
Returns:
|
218
|
+
Dict representation of XML
|
219
|
+
"""
|
220
|
+
try:
|
221
|
+
# Parse XML if string
|
222
|
+
if isinstance(root, str):
|
223
|
+
if root.startswith('<'):
|
224
|
+
root = ET.fromstring(root)
|
225
|
+
else:
|
226
|
+
root = ET.parse(root).getroot()
|
227
|
+
|
228
|
+
result = {}
|
229
|
+
|
230
|
+
# Add attributes if present and requested
|
231
|
+
if preserve_attrs and root.attrib:
|
232
|
+
result['@attributes'] = dict(root.attrib)
|
233
|
+
|
234
|
+
# Add children
|
235
|
+
children = list(root)
|
236
|
+
if not children:
|
237
|
+
text = root.text
|
238
|
+
if text is not None and text.strip():
|
239
|
+
result = text.strip()
|
240
|
+
else:
|
241
|
+
for child in children:
|
242
|
+
child_data = self.xml_to_dict(child, preserve_attrs)
|
243
|
+
if child.tag in result:
|
244
|
+
if not isinstance(result[child.tag], list):
|
245
|
+
result[child.tag] = [result[child.tag]]
|
246
|
+
result[child.tag].append(child_data)
|
247
|
+
else:
|
248
|
+
result[child.tag] = child_data
|
249
|
+
|
250
|
+
return result
|
251
|
+
except Exception as e:
|
252
|
+
error_msg = f"Error converting XML to dict: {str(e)}"
|
253
|
+
logging.error(error_msg)
|
254
|
+
return {}
|
255
|
+
|
256
|
+
def dict_to_xml(
|
257
|
+
self,
|
258
|
+
data: Dict[str, Any],
|
259
|
+
root_tag: str = 'root'
|
260
|
+
) -> Optional[ET.Element]:
|
261
|
+
"""Convert dictionary to XML.
|
262
|
+
|
263
|
+
Args:
|
264
|
+
data: Dictionary to convert
|
265
|
+
root_tag: Tag for root element
|
266
|
+
|
267
|
+
Returns:
|
268
|
+
XML Element tree root
|
269
|
+
"""
|
270
|
+
try:
|
271
|
+
def _create_element(
|
272
|
+
parent: ET.Element,
|
273
|
+
key: str,
|
274
|
+
value: Any
|
275
|
+
):
|
276
|
+
"""Create XML element from key-value pair."""
|
277
|
+
if key == '@attributes':
|
278
|
+
for attr_key, attr_val in value.items():
|
279
|
+
parent.set(attr_key, str(attr_val))
|
280
|
+
elif isinstance(value, dict):
|
281
|
+
child = ET.SubElement(parent, key)
|
282
|
+
for k, v in value.items():
|
283
|
+
_create_element(child, k, v)
|
284
|
+
elif isinstance(value, list):
|
285
|
+
for item in value:
|
286
|
+
child = ET.SubElement(parent, key)
|
287
|
+
if isinstance(item, dict):
|
288
|
+
for k, v in item.items():
|
289
|
+
_create_element(child, k, v)
|
290
|
+
else:
|
291
|
+
child.text = str(item)
|
292
|
+
else:
|
293
|
+
child = ET.SubElement(parent, key)
|
294
|
+
child.text = str(value)
|
295
|
+
|
296
|
+
root = ET.Element(root_tag)
|
297
|
+
for key, value in data.items():
|
298
|
+
_create_element(root, key, value)
|
299
|
+
|
300
|
+
return root
|
301
|
+
except Exception as e:
|
302
|
+
error_msg = f"Error converting dict to XML: {str(e)}"
|
303
|
+
logging.error(error_msg)
|
304
|
+
return None
|
305
|
+
|
306
|
+
def xpath_query(
|
307
|
+
self,
|
308
|
+
root: Union[str, ET.Element],
|
309
|
+
query: str,
|
310
|
+
namespaces: Optional[Dict[str, str]] = None
|
311
|
+
) -> List[ET.Element]:
|
312
|
+
"""Execute XPath query on XML.
|
313
|
+
|
314
|
+
Args:
|
315
|
+
root: XML string or Element tree root
|
316
|
+
query: XPath query string
|
317
|
+
namespaces: Optional namespace mappings
|
318
|
+
|
319
|
+
Returns:
|
320
|
+
List of matching elements
|
321
|
+
"""
|
322
|
+
try:
|
323
|
+
# Parse XML if string
|
324
|
+
if isinstance(root, str):
|
325
|
+
if root.startswith('<'):
|
326
|
+
if util.find_spec('lxml') is None:
|
327
|
+
error_msg = "lxml package is not available. Please install it using: pip install lxml"
|
328
|
+
logging.error(error_msg)
|
329
|
+
return []
|
330
|
+
import lxml.etree as lxml_etree
|
331
|
+
tree = lxml_etree.fromstring(root)
|
332
|
+
else:
|
333
|
+
tree = ET.parse(root)
|
334
|
+
else:
|
335
|
+
if util.find_spec('lxml') is None:
|
336
|
+
error_msg = "lxml package is not available. Please install it using: pip install lxml"
|
337
|
+
logging.error(error_msg)
|
338
|
+
return []
|
339
|
+
import lxml.etree as lxml_etree
|
340
|
+
tree = lxml_etree.fromstring(
|
341
|
+
ET.tostring(root, encoding='unicode')
|
342
|
+
)
|
343
|
+
|
344
|
+
# Execute query
|
345
|
+
results = tree.xpath(
|
346
|
+
query,
|
347
|
+
namespaces=namespaces or {}
|
348
|
+
)
|
349
|
+
|
350
|
+
# Convert results to standard ElementTree elements
|
351
|
+
return [
|
352
|
+
ET.fromstring(lxml_etree.tostring(elem, encoding='unicode'))
|
353
|
+
for elem in results
|
354
|
+
]
|
355
|
+
except Exception as e:
|
356
|
+
error_msg = f"Error executing XPath query: {str(e)}"
|
357
|
+
logging.error(error_msg)
|
358
|
+
return []
|
359
|
+
|
360
|
+
# Create instance for direct function access
|
361
|
+
_xml_tools = XMLTools()
|
362
|
+
read_xml = _xml_tools.read_xml
|
363
|
+
write_xml = _xml_tools.write_xml
|
364
|
+
transform_xml = _xml_tools.transform_xml
|
365
|
+
validate_xml = _xml_tools.validate_xml
|
366
|
+
xml_to_dict = _xml_tools.xml_to_dict
|
367
|
+
dict_to_xml = _xml_tools.dict_to_xml
|
368
|
+
xpath_query = _xml_tools.xpath_query
|
369
|
+
|
370
|
+
if __name__ == "__main__":
|
371
|
+
print("\n==================================================")
|
372
|
+
print("XMLTools Demonstration")
|
373
|
+
print("==================================================\n")
|
374
|
+
|
375
|
+
# Create temporary files
|
376
|
+
import tempfile
|
377
|
+
import os
|
378
|
+
|
379
|
+
temp_file = tempfile.mktemp(suffix='.xml')
|
380
|
+
try:
|
381
|
+
print("1. Creating XML Document")
|
382
|
+
print("------------------------------")
|
383
|
+
xml_content = """<?xml version="1.0" encoding="UTF-8"?>
|
384
|
+
<bookstore>
|
385
|
+
<book category="fiction">
|
386
|
+
<title>The Great Gatsby</title>
|
387
|
+
<author>F. Scott Fitzgerald</author>
|
388
|
+
<year>1925</year>
|
389
|
+
<price>10.99</price>
|
390
|
+
</book>
|
391
|
+
<book category="non-fiction">
|
392
|
+
<title>A Brief History of Time</title>
|
393
|
+
<author>Stephen Hawking</author>
|
394
|
+
<year>1988</year>
|
395
|
+
<price>15.99</price>
|
396
|
+
</book>
|
397
|
+
</bookstore>"""
|
398
|
+
|
399
|
+
with open(temp_file, 'w') as f:
|
400
|
+
f.write(xml_content)
|
401
|
+
print("Sample XML file created")
|
402
|
+
print()
|
403
|
+
|
404
|
+
print("2. Parsing XML")
|
405
|
+
print("------------------------------")
|
406
|
+
result = read_xml(temp_file)
|
407
|
+
print("XML structure:")
|
408
|
+
print(minidom.parseString(ET.tostring(result, encoding='unicode')).toprettyxml(indent=' '))
|
409
|
+
print()
|
410
|
+
|
411
|
+
print("3. Querying XML")
|
412
|
+
print("------------------------------")
|
413
|
+
xpath = "//book[@category='fiction']/title/text()"
|
414
|
+
result = xpath_query(result, xpath)
|
415
|
+
print(f"Fiction book titles (XPath: {xpath}):")
|
416
|
+
for title in result:
|
417
|
+
print(title.text)
|
418
|
+
print()
|
419
|
+
|
420
|
+
print("4. Validating XML")
|
421
|
+
print("------------------------------")
|
422
|
+
schema_file = tempfile.mktemp(suffix='.xsd')
|
423
|
+
schema_content = """<?xml version="1.0" encoding="UTF-8"?>
|
424
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
425
|
+
<xs:element name="bookstore">
|
426
|
+
<xs:complexType>
|
427
|
+
<xs:sequence>
|
428
|
+
<xs:element name="book" maxOccurs="unbounded">
|
429
|
+
<xs:complexType>
|
430
|
+
<xs:sequence>
|
431
|
+
<xs:element name="title" type="xs:string"/>
|
432
|
+
<xs:element name="author" type="xs:string"/>
|
433
|
+
<xs:element name="year" type="xs:integer"/>
|
434
|
+
<xs:element name="price" type="xs:decimal"/>
|
435
|
+
</xs:sequence>
|
436
|
+
<xs:attribute name="category" type="xs:string"/>
|
437
|
+
</xs:complexType>
|
438
|
+
</xs:element>
|
439
|
+
</xs:sequence>
|
440
|
+
</xs:complexType>
|
441
|
+
</xs:element>
|
442
|
+
</xs:schema>"""
|
443
|
+
with open(schema_file, 'w') as f:
|
444
|
+
f.write(schema_content)
|
445
|
+
result, error = validate_xml(temp_file, schema_file)
|
446
|
+
print(f"XML validation result: {result}")
|
447
|
+
if error:
|
448
|
+
print(f"Error: {error}")
|
449
|
+
print()
|
450
|
+
|
451
|
+
print("5. Transforming XML")
|
452
|
+
print("------------------------------")
|
453
|
+
xslt_content = """<?xml version="1.0" encoding="UTF-8"?>
|
454
|
+
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
455
|
+
<xsl:template match="/">
|
456
|
+
<html>
|
457
|
+
<body>
|
458
|
+
<h2>Bookstore Inventory</h2>
|
459
|
+
<table>
|
460
|
+
<tr>
|
461
|
+
<th>Title</th>
|
462
|
+
<th>Author</th>
|
463
|
+
<th>Price</th>
|
464
|
+
</tr>
|
465
|
+
<xsl:for-each select="bookstore/book">
|
466
|
+
<tr>
|
467
|
+
<td><xsl:value-of select="title"/></td>
|
468
|
+
<td><xsl:value-of select="author"/></td>
|
469
|
+
<td><xsl:value-of select="price"/></td>
|
470
|
+
</tr>
|
471
|
+
</xsl:for-each>
|
472
|
+
</table>
|
473
|
+
</body>
|
474
|
+
</html>
|
475
|
+
</xsl:template>
|
476
|
+
</xsl:stylesheet>"""
|
477
|
+
|
478
|
+
xslt_file = tempfile.mktemp(suffix='.xslt')
|
479
|
+
with open(xslt_file, 'w') as f:
|
480
|
+
f.write(xslt_content)
|
481
|
+
|
482
|
+
output_file = tempfile.mktemp(suffix='.html')
|
483
|
+
result = transform_xml(temp_file, xslt_file, output_file)
|
484
|
+
print(f"XML transformation result: {result}")
|
485
|
+
if result and os.path.exists(output_file):
|
486
|
+
print("\nTransformed HTML content:")
|
487
|
+
with open(output_file, 'r') as f:
|
488
|
+
print(f.read())
|
489
|
+
|
490
|
+
finally:
|
491
|
+
# Clean up temporary files
|
492
|
+
for file in [temp_file, schema_file, xslt_file, output_file]:
|
493
|
+
if os.path.exists(file):
|
494
|
+
os.unlink(file)
|
495
|
+
|
496
|
+
print("\n==================================================")
|
497
|
+
print("Demonstration Complete")
|
498
|
+
print("==================================================")
|