XML节点引用实现及对应XSD Schema构建技术咨询
Absolutely—this is a common requirement, and XSD has two solid ways to handle it: key/keyref constraints (the most flexible option for your scenario) and the older ID/IDREF mechanism. Let's break down both with your example in mind.
Approach 1: Key/Keyref (Recommended)
This method is better if your id is an element (like in your example) because it doesn't force you to switch to attributes. It also lets you define custom validation rules that ensure references are valid.
Example Valid XML
First, let's fix your XML to have a root element (required for well-formed XML) and make the reference explicit (I'll use a <ref> element with a target-id attribute):
<root> <data type="String"> <id>1</id> <value>hello</value> </data> <data type="Integer"> <id>2</id> <value>12345</value> </data> <function> <args> <ref target-id="1"/> <!-- Points to the data node with id="1" --> </args> <code>console.log($arg1)</code> </function> </root>
Corresponding XSD Schema
This schema does two key things:
- Ensures all
<data><id>values are unique (using akey) - Ensures every
<ref>'starget-idmatches an existing<data><id>(using akeyref)
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element name="data" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="id" type="xs:string"/> <xs:element name="value" type="xs:string"/> </xs:sequence> <xs:attribute name="type" type="xs:string" use="required"/> </xs:complexType> </xs:element> <xs:element name="function" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="args"> <xs:complexType> <xs:sequence> <xs:element name="ref" maxOccurs="unbounded"> <xs:complexType> <xs:attribute name="target-id" type="xs:string" use="required"/> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="code" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> <!-- Rule: All data/id values must be unique --> <xs:key name="UniqueDataId"> <xs:selector xpath="./data"/> <!-- Select all <data> nodes --> <xs:field xpath="id"/> <!-- Use their <id> element as the key --> </xs:key> <!-- Rule: ref/target-id must match an existing data/id --> <xs:keyref name="DataReference" refer="UniqueDataId"> <xs:selector xpath="./function/args/ref"/> <!-- Select all <ref> nodes --> <xs:field xpath="@target-id"/> <!-- Match their target-id attribute to the key --> </xs:keyref> </xs:element> </xs:schema>
Approach 2: ID/IDREF Attributes
If you don't mind changing your <id> from an element to an attribute, you can use the older ID/IDREF system. XML requires ID values to be attributes, so this is a more restrictive approach but simpler for basic cases.
Adjusted XML
<root> <data type="String" id="1"> <value>hello</value> </data> <data type="Integer" id="2"> <value>12345</value> </data> <function> <args> <ref target-id="1"/> <!-- Links to data@id="1" --> </args> <code>console.log($arg1)</code> </function> </root>
Corresponding XSD
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element name="data" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="value" type="xs:string"/> </xs:sequence> <xs:attribute name="type" type="xs:string" use="required"/> <xs:attribute name="id" type="xs:ID" use="required"/> <!-- Mark as ID --> </xs:complexType> </xs:element> <xs:element name="function" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="args"> <xs:complexType> <xs:sequence> <xs:element name="ref" maxOccurs="unbounded"> <xs:complexType> <xs:attribute name="target-id" type="xs:IDREF" use="required"/> <!-- Mark as IDREF --> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="code" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
Quick Comparison
- Key/Keyref: More flexible (works with elements/attributes, no restrictions on ID format), better for complex scenarios.
- ID/IDREF: Simpler but restrictive (ID must be an attribute, values must start with a letter/underscore).
Either way, your XML will be validated to ensure references point to existing nodes—no broken links allowed!
内容的提问来源于stack exchange,提问作者Peter

