Document Purpose: Explain why taxonomy browsers are essential, what they need to display, how to implement them, and how to derive paths to selected entry points for use in processors and tools
Last Updated: January 2026
Target Audience: XBRL tool developers, UI/UX designers, system integrators
The Problem:
Modern taxonomy packages contain multiple taxonomies and multiple entry points. Users need to:
Without a browser:
User receives: "eba-corep-finrep-3.4.zip"
Questions:
- What's inside?
- Which entry point do I need?
- How do I reference it?
- What's the difference between options?
Result: Trial and error, confusion, errors
With a taxonomy browser:
User receives: "eba-corep-finrep-3.4.zip"
Browser shows:
├─ COREP Entry Points (15 options)
│ ├─ Full COREP (All templates)
│ ├─ COREP - Large Institutions
│ ├─ COREP - Small Institutions
│ └─ ...
├─ FINREP Entry Points (12 options)
│ ├─ Full FINREP (All templates)
│ ├─ FINREP - Credit Institutions
│ └─ ...
User selects: "COREP - Large Institutions"
Browser provides: Path + metadata for processor
Result: Correct choice, proper configuration
Key Capabilities:
Use Cases:
Modern taxonomy packages are NOT simple.
us-gaap-2024.zip (230 MB)
├─ META-INF/
│ └─ taxonomyPackage.xml (package metadata)
├─ schemas/
│ ├─ us-gaap/
│ │ └─ 2024/
│ │ ├─ us-gaap-2024.xsd (10,000+ concepts)
│ │ ├─ dei-2024.xsd
│ │ ├─ currency-2024.xsd
│ │ └─ ...
├─ linkbases/
│ ├─ us-gaap-2024-calculation.xml
│ ├─ us-gaap-2024-definition.xml
│ ├─ us-gaap-2024-label.xml
│ ├─ us-gaap-2024-presentation.xml
│ ├─ us-gaap-2024-reference.xml
│ └─ ...
└─ ...
Entry Points Defined:
├─ "Full US GAAP Taxonomy"
│ URI: http://xbrl.fasb.org/us-gaap/2024/entire/us-gaap-entryPoint-all-2024.xsd
│ Description: Complete taxonomy with all 10,000+ concepts
│ Use case: Companies that need access to all concepts
│
├─ "Core US GAAP Taxonomy"
│ URI: http://xbrl.fasb.org/us-gaap/2024/elts/us-gaap-core-2024.xsd
│ Description: Core concepts only (~2,000 concepts)
│ Use case: Smaller companies with standard reporting
│
├─ "Disclosure Topics - Banking"
│ URI: http://xbrl.fasb.org/us-gaap/2024/elts/us-gaap-banking-2024.xsd
│ Description: Banking-specific concepts
│ Use case: Banking institutions
│
└─ ... (10+ entry points)
Question: Which entry point should a user choose?
Without browser: Read 100-page documentation, guess, try, fail, retry
With browser: See descriptions, make informed choice in 2 minutes
eba-corep-finrep-3.4.zip (450 MB)
├─ META-INF/
│ └─ taxonomyPackage.xml
├─ www.eba.europa.eu/
│ └─ eu/fr/xbrl/crr/fws/corep/its-2024/
│ ├─ mod/
│ │ ├─ cor.xsd (COREP modules)
│ │ ├─ fin.xsd (FINREP modules)
│ │ └─ ...
│ └─ ...
Entry Points (27 total!):
├─ COREP Entry Points (15 options)
│ ├─ "Full COREP Taxonomy"
│ │ Templates: All 70+ templates
│ │ Target: Institutions reporting all modules
│ │
│ ├─ "COREP - Large Institutions"
│ │ Templates: 55 templates
│ │ Target: Credit institutions > €30bn assets
│ │
│ ├─ "COREP - Small Institutions"
│ │ Templates: 25 templates
│ │ Target: Credit institutions < €30bn assets
│ │
│ ├─ "COREP - Investment Firms"
│ │ Templates: 30 templates
│ │ Target: Investment firms
│ │
│ └─ ... (11 more variations)
│
└─ FINREP Entry Points (12 options)
├─ "Full FINREP Taxonomy"
├─ "FINREP - Credit Institutions - Consolidated"
├─ "FINREP - Credit Institutions - Solo"
├─ "FINREP - Investment Firms"
└─ ... (8 more)
Questions users face:
Without browser: Overwhelming, error-prone selection
With browser: Clear comparison, guided selection
Once an entry point is selected, how do you reference it?
Problem: Entry points can be referenced multiple ways:
Entry Point: "COREP - Large Institutions"
Possible references:
1. File path in package:
www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/its-2024/cor_all_ce_con.xsd
2. Absolute URL (if package is published):
https://www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/its-2024/cor_all_ce_con.xsd
3. Package-relative URL:
/www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/its-2024/cor_all_ce_con.xsd
4. Entry point name (from taxonomyPackage.xml):
cor_all_ce_con
5. Catalog resolution URI:
http://www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/its-2024/cor_all_ce_con.xsd
Different tools need different formats!
Browser must provide ALL necessary formats.
Scenario: Configure MuleSoft to generate COREP reports
Step 1: User uploads eba-corep-finrep-3.4.zip to MuleSoft
Step 2: MuleSoft shows taxonomy browser
Step 3: User selects "COREP - Large Institutions"
Step 4: Browser provides entry point URI to GLOMIDCO connector
Step 5: GLOMIDCO generates schemas for this entry point
Step 6: User maps data to schemas
Without browser: User must manually specify URI (error-prone)
With browser: Visual selection, automatic configuration
Scenario: Generate JSON Schema for specific entry point
User: "Generate schema for Small Institutions COREP"
Browser:
├─ Shows all COREP entry points
├─ User selects "COREP - Small Institutions"
├─ Browser highlights included templates
│ └─ Shows: C 01.00, C 02.00, ..., C 25.00 (25 templates)
├─ User confirms selection
└─ Schema generator uses selected entry point
Scenario: Set up XBRL validator for specific reporting requirements
Regulator: "You must validate against FINREP - Credit Institutions - Consolidated"
User:
├─ Loads taxonomy package
├─ Browser shows FINREP entry points
├─ Selects "FINREP - Credit Institutions - Consolidated"
├─ Validator configured with correct entry point
└─ Ready to validate submissions
Scenario: Company preparing SEC 10-K
Company: "We're a small bank. Which entry point do we use?"
Browser shows:
├─ US GAAP Entry Points
│ ├─ Full Taxonomy
│ │ Description: 10,000+ concepts, all industries
│ │ Size: Large
│ │ Recommendation: Only if you need specialized concepts
│ │
│ ├─ Core Taxonomy
│ │ Description: 2,000 core concepts
│ │ Size: Medium
│ │ Recommendation: Most companies
│ │
│ └─ Banking Taxonomy
│ Description: Core + banking concepts
│ Size: Medium
│ Recommendation: ✓ Best for banks
│ Templates included: Balance sheet, Income statement, Banking disclosures
│
└─ User selects: "Banking Taxonomy"
High-level metadata from taxonomyPackage.xml:
Package Information:
┌──────────────────────────────────────────────────┐
│ Package Name: EBA COREP & FINREP Taxonomy 3.4 │
│ Publisher: European Banking Authority │
│ Version: 3.4 │
│ Publication Date: 2024-01-15 │
│ License: https://www.eba.europa.eu/license │
│ Documentation: https://www.eba.europa.eu/docs │
│ │
│ Contents: │
│ ├─ Taxonomies: 2 (COREP, FINREP) │
│ ├─ Entry Points: 27 │
│ ├─ Schemas: 145 files │
│ ├─ Linkbases: 380 files │
│ └─ Size: 450 MB │
└──────────────────────────────────────────────────┘
Tree view showing organization:
📦 EBA COREP & FINREP 3.4
│
├─ 📂 COREP (Common Reporting)
│ │
│ ├─ 📄 Full COREP Taxonomy
│ │ Type: Comprehensive
│ │ Templates: 70
│ │ Target: All reporting institutions
│ │
│ ├─ 📁 By Institution Size
│ │ ├─ 📄 COREP - Large Institutions
│ │ │ Templates: 55
│ │ │ Target: Assets > €30bn
│ │ │ Modules: All prudential modules
│ │ │
│ │ ├─ 📄 COREP - Medium Institutions
│ │ │ Templates: 40
│ │ │ Target: €1bn < Assets < €30bn
│ │ │ Modules: Reduced set
│ │ │
│ │ └─ 📄 COREP - Small Institutions
│ │ Templates: 25
│ │ Target: Assets < €1bn
│ │ Modules: Minimum required
│ │
│ ├─ 📁 By Institution Type
│ │ ├─ 📄 COREP - Credit Institutions
│ │ ├─ 📄 COREP - Investment Firms
│ │ └─ 📄 COREP - Payment Institutions
│ │
│ └─ 📁 By Reporting Basis
│ ├─ 📄 COREP - Consolidated
│ └─ 📄 COREP - Solo
│
└─ 📂 FINREP (Financial Reporting)
│
├─ 📄 Full FINREP Taxonomy
│
├─ 📁 By Institution Type
│ ├─ 📄 FINREP - Credit Institutions - Consolidated
│ ├─ 📄 FINREP - Credit Institutions - Solo
│ └─ 📄 FINREP - Investment Firms
│
└─ 📁 By Accounting Framework
├─ 📄 FINREP - IFRS
└─ 📄 FINREP - National GAAP
When user selects an entry point, show comprehensive details:
┌────────────────────────────────────────────────────────┐
│ COREP - Large Institutions │
├────────────────────────────────────────────────────────┤
│ │
│ Basic Information │
│ ───────────────────────────────────────────────────── │
│ Name: COREP - Large Institutions (Consolidated) │
│ Identifier: cor_all_ce_con │
│ Version: 3.4 │
│ Status: Final │
│ │
│ Description │
│ ───────────────────────────────────────────────────── │
│ Common reporting framework for large credit │
│ institutions (total assets exceeding EUR 30 billion) │
│ under CRR/CRDIV requirements. Includes all │
│ prudential reporting templates applicable to large │
│ institutions on a consolidated basis. │
│ │
│ Target Audience │
│ ───────────────────────────────────────────────────── │
│ ✓ Credit institutions (banks) │
│ ✓ Total assets > €30 billion │
│ ✓ Consolidated reporting basis │
│ ✗ Investment firms (use different entry point) │
│ ✗ Small institutions (use COREP - Small) │
│ │
│ Content Summary │
│ ───────────────────────────────────────────────────── │
│ Total Templates: 55 │
│ Concepts: ~15,000 │
│ Dimensions: 28 │
│ Tables: 55 │
│ │
│ Included Modules │
│ ───────────────────────────────────────────────────── │
│ ✓ C 01.00 - Own Funds │
│ ✓ C 02.00 - Own Funds Requirements │
│ ✓ C 03.00 - Credit Risk - Standardised Approach │
│ ✓ C 04.00 - Credit Risk - IRB Approach │
│ ✓ C 08.00 - Large Exposures │
│ ✓ C 09.00 - Geographical Breakdown │
│ ... (49 more) │
│ │
│ Languages Available │
│ ───────────────────────────────────────────────────── │
│ • English (en) │
│ • French (fr) │
│ • German (de) │
│ • Spanish (es) │
│ • Italian (it) │
│ • Portuguese (pt) │
│ ... (22 languages total) │
│ │
│ Technical Details │
│ ───────────────────────────────────────────────────── │
│ Entry Point URI: │
│ http://www.eba.europa.eu/eu/fr/xbrl/crr/fws/ │
│ corep/its-2024/cor_all_ce_con.xsd │
│ │
│ Package Path: │
│ www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/ │
│ its-2024/cor_all_ce_con.xsd │
│ │
│ Dependencies: │
│ • EBA Common Module 3.4 │
│ • XBRL Dimensions 1.0 │
│ • Table Linkbase 1.0 │
│ │
│ Last Updated: 2024-01-15 │
│ Effective From: 2024-06-30 │
│ │
│ Documentation │
│ ───────────────────────────────────────────────────── │
│ 📄 Data Point Model (DPM) │
│ 📄 Validation Rules │
│ 📄 User Guide │
│ 📄 Migration Guide (from 3.3) │
│ │
└────────────────────────────────────────────────────────┘
[Select This Entry Point] [View Taxonomy] [Export Metadata]
Allow users to compare entry points side-by-side:
┌─────────────────────────────────────────────────────────────────┐
│ Compare Entry Points │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Large Medium Small │
│ Institutions Institutions Institutions │
│ ─────────────────────────────────────────────────────────────── │
│ Asset Threshold > €30bn €1bn - €30bn < €1bn │
│ Templates 55 40 25 │
│ Complexity High Medium Low │
│ Reporting Freq. Quarterly Quarterly Semi-annual │
│ │
│ Modules Included: │
│ ─────────────────────────────────────────────────────────────── │
│ Own Funds ✓ ✓ ✓ │
│ Own Funds Req. ✓ ✓ ✓ │
│ Credit Risk SA ✓ ✓ ✓ │
│ Credit Risk IRB ✓ ✓ ✗ │
│ Large Exposures ✓ ✓ ✗ │
│ Market Risk ✓ ✓ ✗ │
│ Operational Risk ✓ ✓ ✓ │
│ Leverage Ratio ✓ ✓ ✓ │
│ Liquidity ✓ ✓ ○ (Simplified)│
│ ... ... ... ... │
│ │
│ File Size ~180 MB ~120 MB ~60 MB │
│ Concepts ~15,000 ~10,000 ~5,000 │
│ │
└─────────────────────────────────────────────────────────────────┘
Which best describes your institution?
[Large] [Medium] [Small] [Not Sure - Help Me Choose]
Enable users to find entry points quickly:
┌────────────────────────────────────────────────────────┐
│ Search Entry Points │
├────────────────────────────────────────────────────────┤
│ │
│ Search: [investment firms____________] 🔍 │
│ │
│ Filters: │
│ ☑ COREP ☐ FINREP │
│ ☑ Consolidated ☐ Solo │
│ ☐ Large ☐ Medium ☐ Small │
│ │
│ Results (2): │
│ ────────────────────────────────────────────────────── │
│ 1. COREP - Investment Firms │
│ Templates: 30 | Basis: Consolidated │
│ Match: "investment firms" in title and description │
│ │
│ 2. FINREP - Investment Firms │
│ Templates: 20 | Basis: Consolidated │
│ Match: "investment firms" in target audience │
│ │
└────────────────────────────────────────────────────────┘
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
public class TaxonomyBrowserGUI extends JFrame {
private JTree entryPointTree;
private JTextArea detailsPanel;
private TaxonomyPackage loadedPackage;
public TaxonomyBrowserGUI() {
setTitle("XBRL Taxonomy Browser");
setSize(1200, 800);
setLayout(new BorderLayout());
// Left panel: Entry point tree
JPanel leftPanel = createTreePanel();
add(leftPanel, BorderLayout.WEST);
// Right panel: Details
JPanel rightPanel = createDetailsPanel();
add(rightPanel, BorderLayout.CENTER);
// Bottom panel: Actions
JPanel bottomPanel = createActionPanel();
add(bottomPanel, BorderLayout.SOUTH);
}
private JPanel createTreePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(400, 600));
// Tree model
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Loading...");
entryPointTree = new JTree(root);
entryPointTree.addTreeSelectionListener(e -> {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) e.getPath().getLastPathComponent();
if (node.getUserObject() instanceof EntryPoint) {
displayEntryPointDetails((EntryPoint) node.getUserObject());
}
});
JScrollPane scrollPane = new JScrollPane(entryPointTree);
panel.add(scrollPane, BorderLayout.CENTER);
// Toolbar
JToolBar toolbar = new JToolBar();
JButton openButton = new JButton("Open Package...");
openButton.addActionListener(e -> openTaxonomyPackage());
toolbar.add(openButton);
JButton refreshButton = new JButton("Refresh");
refreshButton.addActionListener(e -> refreshTree());
toolbar.add(refreshButton);
panel.add(toolbar, BorderLayout.NORTH);
return panel;
}
private void openTaxonomyPackage() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(
new javax.swing.filechooser.FileNameExtensionFilter(
"Taxonomy Packages (*.zip)", "zip"));
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
loadPackage(file);
}
}
private void loadPackage(File packageFile) {
try {
// Parse package
TaxonomyPackageParser parser = new TaxonomyPackageParser();
loadedPackage = parser.parse(packageFile);
// Build tree
DefaultMutableTreeNode root =
new DefaultMutableTreeNode(loadedPackage.getName());
// Group by taxonomy
Map<String, List<EntryPoint>> grouped =
loadedPackage.getEntryPoints().stream()
.collect(Collectors.groupingBy(
EntryPoint::getTaxonomyName));
for (Map.Entry<String, List<EntryPoint>> entry : grouped.entrySet()) {
DefaultMutableTreeNode taxonomyNode =
new DefaultMutableTreeNode(entry.getKey());
root.add(taxonomyNode);
// Group by category
Map<String, List<EntryPoint>> byCategory =
entry.getValue().stream()
.collect(Collectors.groupingBy(
EntryPoint::getCategory));
for (Map.Entry<String, List<EntryPoint>> catEntry :
byCategory.entrySet()) {
DefaultMutableTreeNode categoryNode =
new DefaultMutableTreeNode(catEntry.getKey());
taxonomyNode.add(categoryNode);
for (EntryPoint ep : catEntry.getValue()) {
DefaultMutableTreeNode epNode =
new DefaultMutableTreeNode(ep);
categoryNode.add(epNode);
}
}
}
// Update tree
entryPointTree.setModel(new DefaultTreeModel(root));
expandTree(entryPointTree, 2); // Expand 2 levels
} catch (Exception e) {
JOptionPane.showMessageDialog(this,
"Error loading package: " + e.getMessage(),
"Error",
JOptionPane.ERROR_MESSAGE);
}
}
private void displayEntryPointDetails(EntryPoint ep) {
StringBuilder sb = new StringBuilder();
sb.append("═══════════════════════════════════════\n");
sb.append(ep.getName()).append("\n");
sb.append("═══════════════════════════════════════\n\n");
sb.append("Identifier: ").append(ep.getIdentifier()).append("\n");
sb.append("Version: ").append(ep.getVersion()).append("\n");
sb.append("Status: ").append(ep.getStatus()).append("\n\n");
sb.append("Description:\n");
sb.append(ep.getDescription()).append("\n\n");
sb.append("Target Audience:\n");
for (String audience : ep.getTargetAudience()) {
sb.append(" • ").append(audience).append("\n");
}
sb.append("\n");
sb.append("Content Summary:\n");
sb.append(" Templates: ").append(ep.getTemplateCount()).append("\n");
sb.append(" Concepts: ").append(ep.getConceptCount()).append("\n");
sb.append(" Dimensions: ").append(ep.getDimensionCount()).append("\n\n");
sb.append("Languages: ");
sb.append(String.join(", ", ep.getLanguages())).append("\n\n");
sb.append("Technical Details:\n");
sb.append(" Entry Point URI:\n");
sb.append(" ").append(ep.getEntryPointURI()).append("\n");
sb.append(" Package Path:\n");
sb.append(" ").append(ep.getPackagePath()).append("\n\n");
if (!ep.getDependencies().isEmpty()) {
sb.append("Dependencies:\n");
for (String dep : ep.getDependencies()) {
sb.append(" • ").append(dep).append("\n");
}
}
detailsPanel.setText(sb.toString());
detailsPanel.setCaretPosition(0);
}
private JPanel createDetailsPanel() {
JPanel panel = new JPanel(new BorderLayout());
detailsPanel = new JTextArea();
detailsPanel.setEditable(false);
detailsPanel.setFont(new Font("Monospaced", Font.PLAIN, 12));
detailsPanel.setMargin(new Insets(10, 10, 10, 10));
JScrollPane scrollPane = new JScrollPane(detailsPanel);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private JPanel createActionPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JButton selectButton = new JButton("Select Entry Point");
selectButton.addActionListener(e -> selectCurrentEntryPoint());
panel.add(selectButton);
JButton exportButton = new JButton("Export Metadata");
exportButton.addActionListener(e -> exportMetadata());
panel.add(exportButton);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(e -> dispose());
panel.add(cancelButton);
return panel;
}
private void selectCurrentEntryPoint() {
TreePath path = entryPointTree.getSelectionPath();
if (path == null) {
JOptionPane.showMessageDialog(this,
"Please select an entry point",
"No Selection",
JOptionPane.WARNING_MESSAGE);
return;
}
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (!(node.getUserObject() instanceof EntryPoint)) {
JOptionPane.showMessageDialog(this,
"Please select an entry point, not a category",
"Invalid Selection",
JOptionPane.WARNING_MESSAGE);
return;
}
EntryPoint selected = (EntryPoint) node.getUserObject();
// Show confirmation
int result = JOptionPane.showConfirmDialog(this,
"Selected Entry Point:\n\n" +
" Name: " + selected.getName() + "\n" +
" URI: " + selected.getEntryPointURI() + "\n\n" +
"Use this entry point?",
"Confirm Selection",
JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
// Return selection to caller
onEntryPointSelected(selected);
dispose();
}
}
// Override this method to handle selection
protected void onEntryPointSelected(EntryPoint entryPoint) {
System.out.println("Selected: " + entryPoint.getName());
System.out.println("URI: " + entryPoint.getEntryPointURI());
}
}
import React, { useState, useEffect } from 'react';
import { Tree, Descriptions, Button, Modal, Input } from 'antd';
import { FolderOutlined, FileOutlined } from '@ant-design/icons';
const TaxonomyBrowser = ({ packageUrl, onSelect }) => {
const [treeData, setTreeData] = useState([]);
const [selectedEntryPoint, setSelectedEntryPoint] = useState(null);
const [loading, setLoading] = useState(false);
const [searchText, setSearchText] = useState('');
useEffect(() => {
loadTaxonomyPackage(packageUrl);
}, [packageUrl]);
const loadTaxonomyPackage = async (url) => {
setLoading(true);
try {
// Call API to parse package
const response = await fetch(`/api/taxonomy/parse?url=${encodeURIComponent(url)}`);
const packageData = await response.json();
// Build tree structure
const tree = buildTreeData(packageData);
setTreeData(tree);
} catch (error) {
console.error('Error loading package:', error);
} finally {
setLoading(false);
}
};
const buildTreeData = (packageData) => {
const tree = [];
// Group by taxonomy
const grouped = packageData.entryPoints.reduce((acc, ep) => {
const taxonomy = ep.taxonomyName;
if (!acc[taxonomy]) {
acc[taxonomy] = [];
}
acc[taxonomy].push(ep);
return acc;
}, {});
Object.entries(grouped).forEach(([taxonomy, entryPoints]) => {
const taxonomyNode = {
title: taxonomy,
key: `taxonomy-${taxonomy}`,
icon: <FolderOutlined />,
children: []
};
// Group by category
const byCategory = entryPoints.reduce((acc, ep) => {
const category = ep.category || 'Other';
if (!acc[category]) {
acc[category] = [];
}
acc[category].push(ep);
return acc;
}, {});
Object.entries(byCategory).forEach(([category, eps]) => {
const categoryNode = {
title: category,
key: `category-${taxonomy}-${category}`,
icon: <FolderOutlined />,
children: eps.map(ep => ({
title: ep.name,
key: `ep-${ep.identifier}`,
icon: <FileOutlined />,
data: ep,
isLeaf: true
}))
};
taxonomyNode.children.push(categoryNode);
});
tree.push(taxonomyNode);
});
return tree;
};
const onTreeSelect = (selectedKeys, info) => {
if (info.node.isLeaf && info.node.data) {
setSelectedEntryPoint(info.node.data);
}
};
const handleSelect = () => {
if (selectedEntryPoint) {
onSelect(selectedEntryPoint);
}
};
const filteredTreeData = searchText
? filterTree(treeData, searchText)
: treeData;
return (
<div style={{ display: 'flex', height: '100vh' }}>
{/* Left panel: Tree */}
<div style={{ width: '400px', borderRight: '1px solid #d9d9d9', padding: '16px' }}>
<Input.Search
placeholder="Search entry points..."
value={searchText}
onChange={e => setSearchText(e.target.value)}
style={{ marginBottom: '16px' }}
/>
<Tree
showIcon
defaultExpandAll
treeData={filteredTreeData}
onSelect={onTreeSelect}
loading={loading}
/>
</div>
{/* Right panel: Details */}
<div style={{ flex: 1, padding: '16px', overflow: 'auto' }}>
{selectedEntryPoint ? (
<>
<h2>{selectedEntryPoint.name}</h2>
<Descriptions bordered column={1}>
<Descriptions.Item label="Identifier">
{selectedEntryPoint.identifier}
</Descriptions.Item>
<Descriptions.Item label="Version">
{selectedEntryPoint.version}
</Descriptions.Item>
<Descriptions.Item label="Status">
{selectedEntryPoint.status}
</Descriptions.Item>
<Descriptions.Item label="Description">
{selectedEntryPoint.description}
</Descriptions.Item>
<Descriptions.Item label="Target Audience">
<ul>
{selectedEntryPoint.targetAudience.map((item, idx) => (
<li key={idx}>{item}</li>
))}
</ul>
</Descriptions.Item>
<Descriptions.Item label="Templates">
{selectedEntryPoint.templateCount}
</Descriptions.Item>
<Descriptions.Item label="Concepts">
{selectedEntryPoint.conceptCount}
</Descriptions.Item>
<Descriptions.Item label="Languages">
{selectedEntryPoint.languages.join(', ')}
</Descriptions.Item>
<Descriptions.Item label="Entry Point URI">
<code>{selectedEntryPoint.entryPointURI}</code>
</Descriptions.Item>
<Descriptions.Item label="Package Path">
<code>{selectedEntryPoint.packagePath}</code>
</Descriptions.Item>
</Descriptions>
<div style={{ marginTop: '24px', textAlign: 'right' }}>
<Button type="primary" size="large" onClick={handleSelect}>
Select This Entry Point
</Button>
</div>
</>
) : (
<div style={{ textAlign: 'center', marginTop: '100px', color: '#999' }}>
<FileOutlined style={{ fontSize: '48px' }} />
<p>Select an entry point to view details</p>
</div>
)}
</div>
</div>
);
};
export default TaxonomyBrowser;
# XBRL Taxonomy Browser CLI
$ xbrl-browser --package eba-corep-finrep-3.4.zip
Loading taxonomy package...
Package: EBA COREP & FINREP Taxonomy 3.4
Publisher: European Banking Authority
Entry Points: 27
Available Entry Points:
COREP (15 entry points):
[1] Full COREP Taxonomy (70 templates)
[2] COREP - Large Institutions (55 templates)
[3] COREP - Medium Institutions (40 templates)
[4] COREP - Small Institutions (25 templates)
[5] COREP - Investment Firms (30 templates)
...
FINREP (12 entry points):
[16] Full FINREP Taxonomy (50 templates)
[17] FINREP - Credit Institutions - Consolidated (35 templates)
[18] FINREP - Credit Institutions - Solo (35 templates)
...
Select entry point [1-27]: 2
Selected: COREP - Large Institutions
═══════════════════════════════════════
Identifier: cor_all_ce_con
Version: 3.4
Templates: 55
Target: Credit institutions > €30bn assets
Entry Point URI:
http://www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/its-2024/cor_all_ce_con.xsd
Package Path:
www.eba.europa.eu/eu/fr/xbrl/crr/fws/corep/its-2024/cor_all_ce_con.xsd
Actions:
[c] Confirm selection
[d] Show more details
[v] View included templates
[b] Back to list
[q] Quit
Choice: c
✓ Entry point selected!
Configuration saved to: .xbrl-config.json
{
"package": "eba-corep-finrep-3.4.zip",
"entryPoint": {
"name": "COREP - Large Institutions",
"identifier": "cor_all_ce_con",
"uri": "http://www.eba.europa.eu/.../cor_all_ce_con.xsd",
"path": "www.eba.europa.eu/.../cor_all_ce_con.xsd"
}
}
Use this configuration in your processor:
xbrl-process --config .xbrl-config.json --instance mydata.xbrl
// REST API for taxonomy browsing
@RestController
@RequestMapping("/api/taxonomy")
public class TaxonomyBrowserAPI {
@PostMapping("/parse")
public TaxonomyPackageInfo parsePackage(@RequestParam String url) {
// Download and parse package
TaxonomyPackage pkg = taxonomyService.loadPackage(url);
return TaxonomyPackageInfo.from(pkg);
}
@GetMapping("/entrypoints")
public List<EntryPointInfo> getEntryPoints(@RequestParam String packageId) {
TaxonomyPackage pkg = taxonomyService.getPackage(packageId);
return pkg.getEntryPoints().stream()
.map(EntryPointInfo::from)
.collect(Collectors.toList());
}
@GetMapping("/entrypoint/{id}")
public EntryPointDetails getEntryPointDetails(
@PathVariable String id,
@RequestParam String packageId) {
TaxonomyPackage pkg = taxonomyService.getPackage(packageId);
EntryPoint ep = pkg.getEntryPoint(id);
return EntryPointDetails.from(ep);
}
@PostMapping("/select")
public SelectionResult selectEntryPoint(
@RequestBody EntryPointSelection selection) {
// Validate selection
TaxonomyPackage pkg = taxonomyService.getPackage(selection.getPackageId());
EntryPoint ep = pkg.getEntryPoint(selection.getEntryPointId());
// Generate configuration
ProcessorConfiguration config =
configGenerator.generateConfiguration(pkg, ep);
return SelectionResult.builder()
.entryPoint(ep)
.configuration(config)
.paths(PathResolver.resolve(pkg, ep))
.build();
}
}
Once an entry point is selected, multiple path formats must be provided:
public class PathResolver {
public static EntryPointPaths resolve(
TaxonomyPackage pkg,
EntryPoint entryPoint) {
EntryPointPaths paths = new EntryPointPaths();
// 1. Entry Point Identifier
paths.setIdentifier(entryPoint.getIdentifier());
// 2. Package-relative path
paths.setPackagePath(entryPoint.getHref());
// 3. Absolute file path (if package is local)
if (pkg.isLocal()) {
File packageFile = pkg.getFile();
String relativePath = entryPoint.getHref();
paths.setFilePath(
new File(packageFile.getParent(), relativePath)
.getAbsolutePath());
}
// 4. Resolved URI (via catalog)
String publicId = entryPoint.getPublicId();
if (publicId != null) {
URI resolvedURI = catalogResolver.resolve(publicId);
paths.setResolvedURI(resolvedURI.toString());
}
// 5. Published URL (if available)
String publishedURL = pkg.getPublishedURL();
if (publishedURL != null) {
paths.setPublishedURL(
publishedURL + "/" + entryPoint.getHref());
}
// 6. HTTP URL (if package has web location)
String webLocation = pkg.getWebLocation();
if (webLocation != null) {
paths.setHttpURL(
webLocation + "/" + entryPoint.getHref());
}
return paths;
}
public static class EntryPointPaths {
private String identifier;
private String packagePath;
private String filePath;
private String resolvedURI;
private String publishedURL;
private String httpURL;
// Getters and setters...
public String getPreferredPath(PathType type) {
switch (type) {
case IDENTIFIER:
return identifier;
case FILE:
return filePath != null ? filePath : packagePath;
case URI:
return resolvedURI != null ? resolvedURI : publishedURL;
case HTTP:
return httpURL != null ? httpURL : publishedURL;
default:
return packagePath;
}
}
public Map<String, String> toMap() {
Map<String, String> map = new HashMap<>();
if (identifier != null) map.put("identifier", identifier);
if (packagePath != null) map.put("packagePath", packagePath);
if (filePath != null) map.put("filePath", filePath);
if (resolvedURI != null) map.put("resolvedURI", resolvedURI);
if (publishedURL != null) map.put("publishedURL", publishedURL);
if (httpURL != null) map.put("httpURL", httpURL);
return map;
}
}
}
// Generate paths for different tools
public class ToolConfigurationGenerator {
public String generateForGLOMIDCO(EntryPoint ep, TaxonomyPackage pkg) {
return String.format(
"TaxonomyCompiler.compile(\n" +
" package: \"%s\",\n" +
" entryPoint: \"%s\"\n" +
");",
pkg.getFile().getAbsolutePath(),
ep.getIdentifier()
);
}
public String generateForMuleSoft(EntryPoint ep, TaxonomyPackage pkg) {
return String.format(
"<glomidco-xbrl:create-table>\n" +
" <glomidco-xbrl:taxonomy-package>%s</glomidco-xbrl:taxonomy-package>\n" +
" <glomidco-xbrl:entry-point>%s</glomidco-xbrl:entry-point>\n" +
"</glomidco-xbrl:create-table>",
pkg.getPublishedURL(),
ep.getIdentifier()
);
}
public String generateForArelle(EntryPoint ep, TaxonomyPackage pkg) {
EntryPointPaths paths = PathResolver.resolve(pkg, ep);
return String.format(
"arelleCmdLine \\\n" +
" --plugins xbrlDB \\\n" +
" --import \"%s\" \\\n" +
" --store postgres://...",
paths.getResolvedURI()
);
}
}
DO:
DON'T:
// Cache parsed packages
private LoadingCache<File, TaxonomyPackage> packageCache =
Caffeine.newBuilder()
.maximumSize(10)
.expireAfterAccess(30, TimeUnit.MINUTES)
.build(file -> parser.parse(file));
// Lazy load details
public class EntryPointInfo {
private String identifier;
private String name;
private Supplier<EntryPointDetails> detailsSupplier;
public EntryPointDetails getDetails() {
return detailsSupplier.get();
}
}
// Index for fast search
private Map<String, Set<EntryPoint>> searchIndex;
public void buildSearchIndex(TaxonomyPackage pkg) {
searchIndex = new HashMap<>();
for (EntryPoint ep : pkg.getEntryPoints()) {
indexWords(ep.getName(), ep);
indexWords(ep.getDescription(), ep);
for (String tag : ep.getTags()) {
indexWords(tag, ep);
}
}
}
public class TaxonomyBrowserException extends Exception {
public enum ErrorType {
PACKAGE_NOT_FOUND,
PACKAGE_CORRUPTED,
NO_METADATA,
NO_ENTRY_POINTS,
INVALID_ENTRY_POINT,
UNSUPPORTED_VERSION
}
private ErrorType errorType;
private String userMessage;
private String technicalDetails;
public String getUserFriendlyMessage() {
switch (errorType) {
case PACKAGE_NOT_FOUND:
return "Could not find taxonomy package file. " +
"Please check the file path and try again.";
case PACKAGE_CORRUPTED:
return "Taxonomy package appears to be corrupted. " +
"Try downloading it again.";
case NO_METADATA:
return "This package is missing required metadata. " +
"It may not be a valid taxonomy package.";
case NO_ENTRY_POINTS:
return "No entry points found in this package. " +
"The package may be incomplete or malformed.";
default:
return userMessage;
}
}
}
public class DesignTimeWorkflow {
public Schema generateSchema() {
// Step 1: User selects taxonomy package
File packageFile = showFilePicker();
// Step 2: Browser shows entry points
TaxonomyBrowser browser = new TaxonomyBrowser(packageFile);
EntryPoint selected = browser.showAndWaitForSelection();
if (selected == null) {
return null; // User cancelled
}
// Step 3: User selects viewpoint
Viewpoint viewpoint = showViewpointSelector(selected);
// Step 4: Generate schema
SchemaGenerator generator = new SchemaGenerator();
Schema schema = generator.generateSchema(
packageFile,
selected.getIdentifier(),
viewpoint,
SchemaFormat.JSON_SCHEMA
);
// Step 5: Show generated schema
showSchemaPreview(schema);
// Step 6: Save for middleware
File outputFile = showSaveDialog();
schema.saveTo(outputFile);
return schema;
}
}
// MuleSoft Connector Configuration UI
public class MuleSoftXBRLConnectorConfig extends AbstractConnectorConfig {
@ConfigurationParameter(
displayName = "Taxonomy Package",
description = "XBRL Taxonomy Package (.zip file)",
type = ConfigurationParameter.Type.FILE
)
private File taxonomyPackage;
@ConfigurationParameter(
displayName = "Entry Point",
description = "Select taxonomy entry point",
type = ConfigurationParameter.Type.CUSTOM,
customEditor = "com.glomidco.mulesoft.TaxonomyBrowserEditor"
)
private String entryPointIdentifier;
// Custom editor shows taxonomy browser
public static class TaxonomyBrowserEditor implements CustomEditor {
@Override
public Component createEditor(Object currentValue,
PropertyChangeListener listener) {
JPanel panel = new JPanel(new BorderLayout());
JButton browseButton = new JButton("Browse Entry Points...");
browseButton.addActionListener(e -> {
TaxonomyBrowserDialog dialog =
new TaxonomyBrowserDialog(taxonomyPackage);
dialog.setVisible(true);
if (dialog.getSelectedEntryPoint() != null) {
EntryPoint ep = dialog.getSelectedEntryPoint();
listener.propertyChange(new PropertyChangeEvent(
this, "entryPointIdentifier",
currentValue, ep.getIdentifier()));
}
});
panel.add(browseButton, BorderLayout.CENTER);
return panel;
}
}
}
The Reality:
Taxonomy Browsers Solve This:
Must Have:
Should Have:
7. Comparison views
8. "Help Me Choose" wizards
9. Recent selections
10. Favorites/bookmarks
11. Documentation links
12. Integration APIs
Nice to Have:
13. Template previews
14. Concept browsing
15. Validation rule display
16. Impact analysis
17. Version comparison
18. Collaboration features
For Desktop Tools:
For Web Applications:
For Middleware:
For Command Line:
Taxonomy browsers are NOT optional "nice-to-have" features.
They are essential infrastructure for:
Without a taxonomy browser:
Users struggle, make mistakes, waste time
With a taxonomy browser:
Users navigate confidently, select correctly, work efficiently
GLOMIDCO's approach of combining taxonomy browsers with design-time schema generation and visual mapping is the right architecture for practical XBRL adoption.
This document explains why taxonomy browsers are essential for entry point selection, what they need to display, and how to implement them for integration with XBRL processors and tools.