Skip to content

Commit 5e72d55

Browse files
authored
Merge pull request #102 from lguerard/bdv_read_xml_metadata
Add method to read metadata back from the xml
2 parents e6421c8 + 4e0691e commit 5e72d55

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,4 @@ ignore = [
5353
]
5454

5555
[tool.ruff.lint.pydocstyle]
56-
convention = "numpy"
56+
convention = "numpy"

src/imcflibs/imagej/bdv.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
FuseBigStitcherDatasetIntoOMETiffCommand,
1818
)
1919
from ij import IJ
20+
from java.io import File, FileInputStream, InputStreamReader
21+
from javax.xml.parsers import DocumentBuilderFactory
22+
from org.xml.sax import InputSource
2023

2124
from .. import pathtools
2225
from ..log import LOG as log
@@ -1666,3 +1669,93 @@ def fuse_dataset_bdvp(
16661669
"compress_temp_files",
16671670
False,
16681671
)
1672+
1673+
1674+
def read_metadata_from_xml(xml_path):
1675+
"""Extract metadata from a Zeiss Lightsheet microscopy XML file.
1676+
1677+
Parse the XML document to retrieve the number of channels, illuminations,
1678+
and timepoints from the experiment metadata.
1679+
1680+
Parameters
1681+
----------
1682+
xml_path : str
1683+
Path to the XML metadata file.
1684+
1685+
Returns
1686+
-------
1687+
dict
1688+
A dictionary containing the following keys:
1689+
- 'channels_count': Number of channels in the dataset
1690+
- 'illuminations_count': Number of illumination directions
1691+
- 'timepoints_count': Number of timepoints in the dataset
1692+
1693+
Examples
1694+
--------
1695+
>>> metadata = read_metadata_from_xml("/path/to/experiment.xml")
1696+
>>> print(metadata["channels_count"])
1697+
... 2
1698+
>>> print(metadata["illuminations_count"])
1699+
... 4
1700+
>>> print(metadata["timepoints_count"])
1701+
... 1
1702+
"""
1703+
# Use our robust XML parsing function
1704+
dbf = DocumentBuilderFactory.newInstance()
1705+
db = dbf.newDocumentBuilder()
1706+
1707+
# Initialize default values
1708+
nbr_chnl = 1
1709+
nbr_ill = 1
1710+
nbr_tp = 1
1711+
1712+
reader = None
1713+
try:
1714+
# This is needed to fix some issues with the micron symbol in the xml file
1715+
reader = InputStreamReader(FileInputStream(File(xml_path)))
1716+
dom = db.parse(InputSource(reader))
1717+
1718+
# Extract channel and illumination counts
1719+
nodeList = dom.getElementsByTagName("Attributes")
1720+
for i in range(nodeList.getLength()):
1721+
name_attr = nodeList.item(i).getAttributes().getNamedItem("name")
1722+
if name_attr is None:
1723+
continue
1724+
1725+
node = name_attr.getNodeValue()
1726+
if node == "channel":
1727+
nbr_chnl = int(
1728+
nodeList.item(i).getElementsByTagName("Channel").getLength()
1729+
)
1730+
if node == "illumination":
1731+
nbr_ill = int(
1732+
nodeList.item(i).getElementsByTagName("Illumination").getLength()
1733+
)
1734+
1735+
# Get timepoints
1736+
timepoints_node = dom.getElementsByTagName("Timepoints")
1737+
if timepoints_node.getLength() > 0:
1738+
last_nodes = timepoints_node.item(0).getElementsByTagName("last")
1739+
if last_nodes.getLength() > 0:
1740+
nbr_tp = int(last_nodes.item(0).getTextContent()) + 1
1741+
except Exception as e:
1742+
# log.exception includes the traceback when available
1743+
try:
1744+
log.exception("Error extracting metadata from XML: %s", e)
1745+
except Exception:
1746+
log.error("Error extracting metadata from XML: %s", str(e))
1747+
finally:
1748+
# Ensure the Java reader is closed to free resources
1749+
try:
1750+
if reader is not None:
1751+
reader.close()
1752+
except Exception:
1753+
pass
1754+
1755+
xml_metadata = {
1756+
"channels_count": nbr_chnl,
1757+
"illuminations_count": nbr_ill,
1758+
"timepoints_count": nbr_tp,
1759+
}
1760+
1761+
return xml_metadata

0 commit comments

Comments
 (0)