praisonaiagents 0.0.22__py3-none-any.whl → 0.0.24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- praisonaiagents/agent/agent.py +22 -33
- praisonaiagents/agents/agents.py +18 -4
- 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.22.dist-info → praisonaiagents-0.0.24.dist-info}/METADATA +1 -1
- praisonaiagents-0.0.24.dist-info/RECORD +42 -0
- praisonaiagents-0.0.22.dist-info/RECORD +0 -24
- {praisonaiagents-0.0.22.dist-info → praisonaiagents-0.0.24.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.22.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("==================================================")
|