Added xsd support

This commit is contained in:
2025-09-07 12:03:21 -06:00
parent 87b6693434
commit c6c476ff76
4 changed files with 486 additions and 119 deletions

51
CLAUDE.md Normal file
View File

@ -0,0 +1,51 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
This is a simple XML requirements viewer application consisting of:
- `xml_requirements_viewer.html` - A standalone HTML application for viewing XML requirements
- `sample_requirements.xml` - A sample XML file containing formatted requirements
## Architecture
The project is a single-page HTML application with embedded CSS and JavaScript. No build process, dependencies, or server is required - it runs entirely in the browser.
### Core Components
- **HTML Structure**: Standard HTML5 with responsive design
- **CSS Styling**: Embedded styles with dark mode support via `@media (prefers-color-scheme: dark)`
- **JavaScript Functionality**:
- Drag-and-drop file handling
- XML parsing using DOMParser
- Dynamic DOM manipulation for requirements display
### XML Structure
The viewer expects XML files with this structure:
```xml
<requirements>
<requirement id="REQ-XXX">
<title>Title</title>
<priority>High/Medium/Low</priority>
<category>Category</category>
<text>HTML-formatted requirement text with custom tags</text>
<status>Active/Draft</status>
</requirement>
</requirements>
```
### Custom XML Tags Supported
The viewer supports various custom formatting tags within `<text>` elements:
- Text formatting: `<strong>`, `<em>`, `<u>`, `<del>`, `<sup>`, `<sub>`, `<mark>`, `<small>`
- Code elements: `<code>`, `<kbd>`, `<samp>`, `<var>`, `<pre>`
- Semantic tags: `<critical>`, `<optional>`, `<deprecated>`, `<todo>`
- Technical tags: `<value>`, `<unit>`, `<term>`, `<acronym>`, `<version>`
- Structure: `<br>`, `<hr>`, `<ul>`, `<ol>`, `<li>`, `<blockquote>`
- References: `<ref>`, `<url>`, `<link>`
## Usage
Open `xml_requirements_viewer.html` in a web browser and drag/drop or select XML files to view formatted requirements.

321
software-rules-html-xml.xml Normal file
View File

@ -0,0 +1,321 @@
<?xml version="1.0" encoding="UTF-8"?>
<SoftwareRules xmlns="http://example.com/software-rules"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.com/software-rules software-rules.xsd"
version="2.0"
lastUpdated="2025-01-15">
<Rule enabled="true">
<ruleId>SEC-001</ruleId>
<ruleName><strong>Password Complexity Check</strong></ruleName>
<category>Security</category>
<priority>Critical</priority>
<status>Active</status>
<description>
Ensures passwords meet <strong>minimum complexity requirements</strong>:
<ul>
<li>At least <mark>12 characters</mark> in length</li>
<li>Contains <em>uppercase</em> and <em>lowercase</em> letters</li>
<li>Includes <u>numbers</u> and special characters</li>
<li>No <s>dictionary words</s> allowed</li>
</ul>
<blockquote>A strong password is your first line of defense.</blockquote>
</description>
<condition><code>password.length >= 13 AND hasUpperCase AND hasLowerCase AND hasNumber AND hasSpecialChar</code></condition>
<action>VALIDATE_PASSWORD</action>
<errorMessage><strong>Error:</strong> Password must be <mark>at least 12 characters</mark> and contain uppercase, lowercase, numbers, and special characters</errorMessage>
<appliesTo>UserRegistration</appliesTo>
<appliesTo>PasswordReset</appliesTo>
<appliesTo>AccountCreation</appliesTo>
<createdBy>admin</createdBy>
<createdDate>2024-01-15</createdDate>
<modifiedBy>security_team</modifiedBy>
<modifiedDate>2024-06-20</modifiedDate>
<tags>authentication</tags>
<tags>security</tags>
<tags>compliance</tags>
<riskLevel>5</riskLevel>
<automationEnabled>true</automationEnabled>
</Rule>
<Rule enabled="true">
<ruleId>PERF-002</ruleId>
<ruleName><em>Query Timeout Limit</em></ruleName>
<category>Performance</category>
<priority>High</priority>
<status>Active</status>
<description>
<h3>Performance Protection Rule</h3>
<p>This rule prevents database queries from running longer than <strong>30 seconds</strong>.</p>
<p>Key settings:</p>
<table>
<tr>
<th>Parameter</th>
<th>Value</th>
</tr>
<tr>
<td>Max Execution Time</td>
<td><code>30000ms</code></td>
</tr>
<tr>
<td>Action</td>
<td>Terminate Query</td>
</tr>
</table>
<hr/>
<small>Note: This limit can be overridden for batch operations.</small>
</description>
<condition><pre>if (query.executionTime > 30000) {
return TERMINATE;
}</pre></condition>
<action>TERMINATE_QUERY</action>
<errorMessage>Query execution exceeded maximum allowed time of <strong>30 seconds</strong></errorMessage>
<appliesTo>DatabaseOperations</appliesTo>
<appliesTo>ReportGeneration</appliesTo>
<createdBy>dba_team</createdBy>
<createdDate>2024-02-10</createdDate>
<modifiedBy>performance_team</modifiedBy>
<modifiedDate>2024-11-05</modifiedDate>
<tags>database</tags>
<tags>performance</tags>
<riskLevel>3</riskLevel>
<automationEnabled>true</automationEnabled>
</Rule>
<Rule enabled="false">
<ruleId>VAL-003</ruleId>
<ruleName>Email Format Validation</ruleName>
<category>DataValidation</category>
<priority>Medium</priority>
<status>Testing</status>
<description>
Validates email addresses against <abbr title="Request for Comments">RFC</abbr> 5322 standard.
<br/><br/>
<strong>Valid format:</strong> <code>user@domain.com</code>
<br/>
<strong>Invalid formats:</strong>
<ul>
<li><del>user@</del></li>
<li><del>@domain.com</del></li>
<li><del>user domain.com</del></li>
</ul>
<details>
<summary>Click for regex pattern</summary>
<code>^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$</code>
</details>
</description>
<condition>email.matches(RFC5322_REGEX)</condition>
<action>VALIDATE_EMAIL</action>
<errorMessage>Please enter a <u>valid email address</u></errorMessage>
<appliesTo>UserProfile</appliesTo>
<appliesTo>ContactForm</appliesTo>
<createdBy>dev_team</createdBy>
<createdDate>2024-03-22</createdDate>
<tags>validation</tags>
<tags>email</tags>
<riskLevel>1</riskLevel>
<automationEnabled>true</automationEnabled>
</Rule>
<Rule enabled="true">
<ruleId>BUS-004</ruleId>
<ruleName>Transaction Amount Limit</ruleName>
<category>BusinessLogic</category>
<priority>High</priority>
<status>Active</status>
<description>
<h4>Transaction Limits by User Tier</h4>
<ol>
<li><strong>Basic Tier:</strong> Maximum $1,000 per transaction</li>
<li><strong>Premium Tier:</strong> Maximum $10,000 per transaction</li>
<li><strong>Enterprise Tier:</strong> Maximum $100,000 per transaction</li>
</ol>
<p>Transactions exceeding these limits will be <mark>automatically blocked</mark> and flagged for review.</p>
<p>For limit increases, contact <a href="mailto:support@example.com">support@example.com</a></p>
</description>
<condition>transaction.amount > user.maxTransactionLimit</condition>
<action>BLOCK_TRANSACTION</action>
<errorMessage>Transaction amount of <strong>${amount}</strong> exceeds your account limit</errorMessage>
<appliesTo>PaymentProcessing</appliesTo>
<appliesTo>WireTransfers</appliesTo>
<appliesTo>ACHTransfers</appliesTo>
<createdBy>compliance_officer</createdBy>
<createdDate>2024-01-05</createdDate>
<modifiedBy>risk_management</modifiedBy>
<modifiedDate>2024-09-15</modifiedDate>
<tags>financial</tags>
<tags>limits</tags>
<tags>risk</tags>
<riskLevel>4</riskLevel>
<automationEnabled>true</automationEnabled>
</Rule>
<Rule enabled="true">
<ruleId>COMP-005</ruleId>
<ruleName><mark>GDPR Data Retention</mark></ruleName>
<category>Compliance</category>
<priority>Critical</priority>
<status>Active</status>
<description>
<h3>⚠️ GDPR Compliance Rule</h3>
<p>Personal data retention must comply with <strong>GDPR Article 5(1)(e)</strong>.</p>
<blockquote>
"Personal data shall be kept in a form which permits identification of data subjects for
<u>no longer than is necessary</u> for the purposes for which the personal data are processed."
</blockquote>
<p><strong>Maximum retention periods:</strong></p>
<dl>
<dt>Customer Data</dt>
<dd>2 years after account closure</dd>
<dt>Employee Data</dt>
<dd>7 years after employment ends</dd>
<dt>Marketing Data</dt>
<dd>1 year after last interaction</dd>
</dl>
<p><small>Reference: <cite>GDPR Regulation (EU) 2016/679</cite></small></p>
</description>
<condition>data.retentionPeriod > 730 AND data.type == 'PERSONAL'</condition>
<action>FLAG_FOR_DELETION</action>
<errorMessage><strong>⚠️ Warning:</strong> Personal data retention period exceeded <mark>GDPR requirements</mark></errorMessage>
<appliesTo>DataManagement</appliesTo>
<appliesTo>UserRecords</appliesTo>
<createdBy>legal_team</createdBy>
<createdDate>2024-05-25</createdDate>
<tags>GDPR</tags>
<tags>privacy</tags>
<tags>compliance</tags>
<riskLevel>5</riskLevel>
<automationEnabled>false</automationEnabled>
</Rule>
<Rule enabled="true">
<ruleId>ACC-006</ruleId>
<ruleName>Multi-Factor Authentication Required</ruleName>
<category>UserAccess</category>
<priority>High</priority>
<status>Active</status>
<description>
<p>MFA is <strong>mandatory</strong> for privileged accounts.</p>
<p>Press <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>M</kbd> to open MFA settings.</p>
<p>Supported methods:</p>
<ul>
<li>📱 SMS verification</li>
<li>📧 Email OTP</li>
<li>🔐 Authenticator app</li>
<li>🔑 Hardware token</li>
</ul>
<p>Formula: <var>security_score</var> = <var>password_strength</var> × <var>mfa_enabled</var><sup>2</sup></p>
</description>
<condition>user.role IN ('admin', 'finance', 'hr') AND !session.hasMFA</condition>
<action>REQUIRE_MFA</action>
<errorMessage><strong>🔒 Security Alert:</strong> Multi-factor authentication is <u>required</u> for this operation</errorMessage>
<appliesTo>AdminPanel</appliesTo>
<appliesTo>FinancialReports</appliesTo>
<appliesTo>EmployeeData</appliesTo>
<createdBy>security_team</createdBy>
<createdDate>2024-04-10</createdDate>
<modifiedBy>ciso</modifiedBy>
<modifiedDate>2024-12-01</modifiedDate>
<tags>security</tags>
<tags>authentication</tags>
<tags>MFA</tags>
<riskLevel>4</riskLevel>
<automationEnabled>true</automationEnabled>
</Rule>
<Rule enabled="true">
<ruleId>SEC-007</ruleId>
<ruleName><strong style="color: red;">SQL Injection Prevention</strong></ruleName>
<category>Security</category>
<priority>Critical</priority>
<status>Active</status>
<description>
<h2>🛡️ Critical Security Rule</h2>
<p>This rule detects and blocks potential SQL injection attempts.</p>
<p><strong>Common injection patterns blocked:</strong></p>
<pre>
SELECT * FROM users WHERE id = '1' OR '1'='1'
DROP TABLE users; --
UNION SELECT * FROM passwords
</pre>
<p>Protection includes:</p>
<ol>
<li><strong>Input validation</strong> - All inputs sanitized</li>
<li><strong>Parameterized queries</strong> - No direct concatenation</li>
<li><strong>Escape sequences</strong> - Special characters handled</li>
</ol>
<figure>
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3Crect width='100' height='100' fill='%23ff0000'/%3E%3Ctext x='50' y='50' text-anchor='middle' fill='white' font-size='40'%3E⚠%3C/text%3E%3C/svg%3E" alt="Warning"/>
<figcaption>High Risk Alert</figcaption>
</figure>
<p><ins>Updated: Now includes NoSQL injection prevention</ins></p>
</description>
<condition><samp>if (detectSQLInjection(input)) { return BLOCK; }</samp></condition>
<action>BLOCK_REQUEST</action>
<errorMessage><span style="color: red; font-weight: bold;">⛔ SECURITY VIOLATION:</span> Potentially malicious input detected and blocked</errorMessage>
<appliesTo>APIEndpoints</appliesTo>
<appliesTo>SearchFunctions</appliesTo>
<createdBy>security_team</createdBy>
<createdDate>2024-01-20</createdDate>
<tags>security</tags>
<tags>injection</tags>
<tags>SQL</tags>
<riskLevel>5</riskLevel>
<automationEnabled>true</automationEnabled>
</Rule>
<Rule enabled="false">
<ruleId>PERF-008</ruleId>
<ruleName>API Rate Limiting</ruleName>
<category>Performance</category>
<priority>Medium</priority>
<status>Deprecated</status>
<description>
<p><s>This rule has been deprecated</s> in favor of the new adaptive rate limiting system.</p>
<p>Previous limits were:</p>
<table>
<thead>
<tr>
<th>Tier</th>
<th>Requests/Hour</th>
<th>Burst Limit</th>
</tr>
</thead>
<tbody>
<tr>
<td>Free</td>
<td>100</td>
<td>10</td>
</tr>
<tr>
<td>Pro</td>
<td>1,000</td>
<td>50</td>
</tr>
<tr>
<td>Enterprise</td>
<td>10,000</td>
<td>500</td>
</tr>
</tbody>
</table>
<address>
For questions, contact:<br/>
API Team<br/>
api-support@example.com
</address>
<time datetime="2024-12-31">Deprecated on December 31, 2024</time>
</description>
<condition>user.apiCalls > 1000 AND timeWindow == '1hour'</condition>
<action>THROTTLE_REQUESTS</action>
<errorMessage>API rate limit exceeded. Please try again later</errorMessage>
<appliesTo>PublicAPI</appliesTo>
<createdBy>api_team</createdBy>
<createdDate>2024-02-28</createdDate>
<tags>API</tags>
<tags>rate-limiting</tags>
<riskLevel>2</riskLevel>
<automationEnabled>true</automationEnabled>
</Rule>
</SoftwareRules>

74
software-rules.xsd.txt Normal file
View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/software-rules"
xmlns:tns="http://example.com/software-rules"
elementFormDefault="qualified">
<!-- Root element -->
<xs:element name="SoftwareRules">
<xs:complexType>
<xs:sequence>
<xs:element name="Rule" type="tns:RuleType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="version" type="xs:string" use="required"/>
<xs:attribute name="lastUpdated" type="xs:date" use="optional"/>
</xs:complexType>
</xs:element>
<!-- Complex type for Rule -->
<xs:complexType name="RuleType">
<xs:sequence>
<xs:element name="ruleId" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="ruleName" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="category" type="tns:CategoryType" minOccurs="1" maxOccurs="1"/>
<xs:element name="priority" type="tns:PriorityType" minOccurs="1" maxOccurs="1"/>
<xs:element name="status" type="tns:StatusType" minOccurs="1" maxOccurs="1"/>
<xs:element name="description" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="condition" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="action" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="errorMessage" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="appliesTo" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="createdBy" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="createdDate" type="xs:date" minOccurs="1" maxOccurs="1"/>
<xs:element name="modifiedBy" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="modifiedDate" type="xs:date" minOccurs="0" maxOccurs="1"/>
<xs:element name="tags" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="riskLevel" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="automationEnabled" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="enabled" type="xs:boolean" default="true"/>
</xs:complexType>
<!-- Enumeration for Category -->
<xs:simpleType name="CategoryType">
<xs:restriction base="xs:string">
<xs:enumeration value="Security"/>
<xs:enumeration value="Performance"/>
<xs:enumeration value="DataValidation"/>
<xs:enumeration value="BusinessLogic"/>
<xs:enumeration value="Compliance"/>
<xs:enumeration value="UserAccess"/>
</xs:restriction>
</xs:simpleType>
<!-- Enumeration for Priority -->
<xs:simpleType name="PriorityType">
<xs:restriction base="xs:string">
<xs:enumeration value="Critical"/>
<xs:enumeration value="High"/>
<xs:enumeration value="Medium"/>
<xs:enumeration value="Low"/>
</xs:restriction>
</xs:simpleType>
<!-- Enumeration for Status -->
<xs:simpleType name="StatusType">
<xs:restriction base="xs:string">
<xs:enumeration value="Active"/>
<xs:enumeration value="Inactive"/>
<xs:enumeration value="Testing"/>
<xs:enumeration value="Deprecated"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

View File

@ -128,7 +128,13 @@
.field-row { .field-row {
display: flex; display: flex;
margin: 8px 0; margin: 8px 0;
padding: 8px 0;
align-items: flex-start; align-items: flex-start;
border-bottom: 1px dotted #e0e0e0;
}
.field-row:last-child {
border-bottom: none;
} }
.field-label { .field-label {
@ -145,6 +151,20 @@
word-wrap: break-word; word-wrap: break-word;
} }
/* Style for multi-value fields */
.field-value-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.field-value-item {
padding: 4px 8px;
background: #f5f5f5;
border-left: 2px solid #007bff;
border-radius: 2px;
}
.element-pair { .element-pair {
position: relative; position: relative;
} }
@ -412,6 +432,10 @@
background: linear-gradient(90deg, transparent, #4fc3f7, transparent); background: linear-gradient(90deg, transparent, #4fc3f7, transparent);
} }
.field-row {
border-bottom-color: #444;
}
.field-label { .field-label {
color: #64b5f6; color: #64b5f6;
} }
@ -420,6 +444,11 @@
color: #e0e0e0; color: #e0e0e0;
} }
.field-value-item {
background: #3d3d3d;
border-left-color: #4fc3f7;
}
.element-index { .element-index {
background: #4fc3f7; background: #4fc3f7;
} }
@ -1012,12 +1041,16 @@
const siblings = Array.from(element.children).filter(c => c.tagName === fieldName); const siblings = Array.from(element.children).filter(c => c.tagName === fieldName);
if (siblings.length > 1) { if (siblings.length > 1) {
// For multi-value fields, combine them // For multi-value fields, create a list
const values = siblings.map(s => formatElementContent(s)).filter(v => v && v !== '<em>(empty)</em>'); const values = siblings.map(s => formatElementContent(s)).filter(v => v && v !== '<em>(empty)</em>');
if (values.length > 0) { if (values.length > 0) {
// Create a formatted list of values
const listHtml = '<div class="field-value-list">' +
values.map(v => `<div class="field-value-item">${v}</div>`).join('') +
'</div>';
fields.push({ fields.push({
name: fieldName, name: fieldName,
value: values.join(', ') value: listHtml
}); });
} }
processedTags.add(fieldName); processedTags.add(fieldName);
@ -1155,124 +1188,12 @@
} }
function formatElementContent(element) { function formatElementContent(element) {
let html = ''; // Simply get the inner HTML of the element, which preserves all HTML formatting
const innerHTML = element.innerHTML;
element.childNodes.forEach(node => { // If there's content, return it as-is (browser will handle HTML tags)
if (node.nodeType === Node.TEXT_NODE) { // If empty, return the (empty) indicator
html += node.textContent; return innerHTML ? innerHTML.trim() : '<em>(empty)</em>';
} else if (node.nodeType === Node.ELEMENT_NODE) {
// Format known tags
const tagName = node.tagName.toLowerCase();
const content = formatElementContent(node);
// Apply appropriate formatting based on tag
switch(tagName) {
case 'strong':
case 'b':
html += `<strong>${content}</strong>`;
break;
case 'em':
case 'i':
html += `<em>${content}</em>`;
break;
case 'u':
html += `<u>${content}</u>`;
break;
case 'del':
case 'strike':
html += `<del>${content}</del>`;
break;
case 'sup':
html += `<sup>${content}</sup>`;
break;
case 'sub':
html += `<sub>${content}</sub>`;
break;
case 'mark':
case 'highlight':
html += `<mark>${content}</mark>`;
break;
case 'small':
html += `<small>${content}</small>`;
break;
case 'code':
html += `<code>${content}</code>`;
break;
case 'kbd':
html += `<kbd>${content}</kbd>`;
break;
case 'samp':
html += `<samp>${content}</samp>`;
break;
case 'var':
html += `<var>${content}</var>`;
break;
case 'pre':
html += `<pre>${content}</pre>`;
break;
case 'critical':
html += `<span class="critical">${content}</span>`;
break;
case 'optional':
html += `<span class="optional">${content}</span>`;
break;
case 'deprecated':
html += `<span class="deprecated">${content}</span>`;
break;
case 'todo':
html += `<span class="todo">${content}</span>`;
break;
case 'value':
html += `<span class="value">${content}</span>`;
break;
case 'unit':
html += `<span class="unit">${content}</span>`;
break;
case 'term':
html += `<span class="term">${content}</span>`;
break;
case 'acronym':
html += `<span class="acronym">${content}</span>`;
break;
case 'version':
html += `<span class="version">${content}</span>`;
break;
case 'br':
html += '<br>';
break;
case 'hr':
html += '<hr>';
break;
case 'ul':
html += `<ul>${content}</ul>`;
break;
case 'ol':
html += `<ol>${content}</ol>`;
break;
case 'li':
html += `<li>${content}</li>`;
break;
case 'blockquote':
html += `<blockquote>${content}</blockquote>`;
break;
case 'ref':
html += `<span class="ref">${content}</span>`;
break;
case 'url':
html += `<span class="url">${content}</span>`;
break;
case 'link':
const href = node.getAttribute('href') || '#';
html += `<a href="${href}" class="url">${content}</a>`;
break;
default:
// For unknown tags, just include the content
html += content;
}
}
});
return html || '<em>(empty)</em>';
} }
function formatXMLElement(element) { function formatXMLElement(element) {