I'm constructing a DTD which has a fuel_system element.
I want to restrict the text between <fuel_system> tag. It must be only carbureted or fuel-injected. How can I do this?
I don't mention something like this = > attribute type (carbureted, fuel-injected), because I want to force this rule in <fuel_system> tags, not the attribute of fuel_system.
when defining an element in a DTD, there is no way to restrict the text inside the element. you can only tell what other element (child elements) it might contain and their order, or you can tell that the element contains text, or a mixture of the 2.
so, basically you have 2 options for restricting the <fuel-system>: either declare it as an attribute (<fuel-system type="fuel-injected"/>), or declare children elements <fuel-injected> and <carburated>. the choice between those 2 options depends on what you are trying to describe and what will change depending on the type of fuel-system.
(the grammar for the declaration of an element is defined here)
examples: first option, attributes
<!ELEMENT fuel-system EMPTY>
<!ATTLIST fuel-system (fuel-injected|carburated) #REQUIRED>
second option, child elements
<!ELEMENT fuel-system (fuel-injected|carburated)>
<!ELEMENT fuel-injected ...>
<!ELEMENT carburated ...>
Does it have to be a DTD? Is XML Schema an option?
Using XML Schema you can restrict element text to an enumerated list of values:
<xs:element name="fuel-system">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="fuel-injected"/>
<xs:enumeration value="carbourated"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Related
I am trying to use DiffBuilder to ignore XML elements order when comparing two .xml files but it fails. I have tried every possible combination and read many articles before posting this question.
For example:
<Data:Keys>
<Data:Value Key="1" Name="Example1" />
<Data:Value Key="2" Name="Example2" />
<Data:Value Key="3" Name="Example3" />
</Data:Keys>
<Data:Keys>
<Data:Value Key="2" Name="Example2" />
<Data:Value Key="1" Name="Example1" />
<Data:Value Key="3" Name="Example3" />
</Data:Keys>
I want these two treated as same XML. Notice that elements are empty, they have only attributes.
What I did so far:
def diff = DiffBuilder.compare(Input.fromString(xmlIN))
.withTest(Input.fromString(xmlOUT))
.ignoreComments()
.ignoreWhitespace()
.checkForSimilar()
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.conditionalBuilder()
.whenElementIsNamed("Data:Keys").thenUse(ElementSelectors.byXPath("./Data:Value",
ElementSelectors.byNameAndText))
.elseUse(ElementSelectors.byName)
.build()))
But it fails every time. I don't know if the issue is the namespace, or that the elements are empty.
Any help will be appricated. Thank you in advance.
if you aim to match tags Data:Value by their attributes together, you should start with this:
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.conditionalBuilder()
.whenElementIsNamed("Data:Value")
and since that tag doesn't have any text, the byNameAndText won't work. You can only work on names and attributes. My advice is to do it like this:
.thenUse(ElementSelectors.byNameAndAttributes("Key"))
or
.thenUse(ElementSelectors.byNameAndAllAttributes())
//equivalent
.thenUse(ElementSelectors.byNameAndAttributes("Key", "Name"))
As of issues with namespaces, checkForSimilar() should output SIMILAR, this means they are not DIFFERENT, so this is what you need. If you didn't use checkForSimilar() the differences in namespaces would be outputed as DIFFERENT.
I encountered the following problems in eXist-db configuring range indexes to specify attributes that are worth indexing.
<collection xmlns="http://exist-db.org/collection-config/1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<index>
<range>
<create qname="tei:term">
<condition attribute="type" value="main"/>
<field name="mainTerm" type="xs:string"/>
</create>
</range>
</index></collection>
Error occurred:"/db/system/config/db/range/collection.xconf cvc-complex-type.2.4.a: Invalid content was found starting with element 'condition'. One of '{"http://exist-db.org/collection-config/1.0":field}' is expected."
Please help me.
The error you are getting is a schema validation error, triggered by the presence of the <condition> element used by the recently introduced conditional combined index feature.
I've submitted a fix to the error, and for now, you can ignore the error. The schema validation error will not have any effect on the functionality.
General Configuration Structure and Syntax
Index configuration collection.xconf files are standard XML documents that have their elements and attributes defined by the eXist-db namespace http://exist-db.org/collection-config/1.0. The following example shows a configuration example:
<collection xmlns="http://exist-db.org/collection-config/1.0">
<index>
<!-- Full text index based on Lucene -->
<lucene>
<text qname="SPEECH">
<ignore qname="SPEAKER"/>
</text>
<text qname="TITLE"/>
</lucene>
<!-- Range indexes -->
<range>
<create qname="title" type="xs:string"/>
<create qname="author" type="xs:string"/>
<create qname="year" type="xs:integer"/>
</range>
<!-- N-gram indexes -->
<ngram qname="author"/>
<ngram qname="title"/>
</index>
</collection>
To use the new range index, wrap the range index definitions into a range element:
<collection xmlns="http://exist-db.org/collection-config/1.0">
<!--from Tamboti-->
<index xmlns:mods="http://www.loc.gov/mods/v3">
<lucene>
<text qname="mods:title"/>
</lucene>
<!-- Range indexes -->
<range>
<create qname="mods:namePart" type="xs:string" case="no"/>
<create qname="mods:dateIssued" type="xs:string"/>
<create qname="#ID" type="xs:string"/>
</range>
</index>
</collection>
Conditional combined indexes
For combined indexes, you can specify conditions to restrict the values being indexed to those contained in elements that have an attribute meeting certain criteria:
<range>
<create qname="tei:term">
<condition attribute="type" value="main"/>
<field name="mainTerm" type="xs:string"/>
</create>
</range>
This will only index the value of the tei:term element if it has an attribute named type with the value main. Multiple conditions can be specified in an index definition, in which case all conditions need to match in order for the value to be indexed.
Make sure you have a valid xml. For further details, you can read the documentation here: https://exist-db.org/exist/apps/doc/newrangeindex.xml
MCVE:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
targetNamespace="http://versionschema.org/xmlns/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:vs="http://versionschema.org/xmlns/"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<xsd:element name="VersionSchema" type="vs:VersionSchema"/>
<xsd:complexType name="VersionSchema" minOccurs="1" maxOccurs="1">
<!-- VS says: "minOccurs and maxOccurs not allowed ^^^^ -->
<xsd:element name="Field" minOccurs="1" maxOccurs="unbounded">
<!-- ^^^ VS says: The 'http://www.w3.org/2001/XMLSchema:element' is not supported in this context -->
</xsd:element>
</xsd:complexType>
</xsd:schema>
Referring to https://www.w3.org/TR/xmlschema-0/#POSchema, I don't see why it's complaining. Any ideas whether or what it is I am doing wrong here?
Note that it is my goal to write this up such that there can be only one VersionSchema object in an XML file.
Your are thinking about this from a programming language perspective in which you would add fields to a class or type by placing them as elements inside of the container.
For XML Schemas this is not true. The reason for this is that in its most strict definition XML is order dependent.
You can write yourself a schema which accepts the following XML.
<Root>
<Element/>
<Test/>
</Root>
But rejects a very similiar XML Structure:
<Root>
<Test/>
<Element/>
</Root>
One of the reasons you can do so is because a more strict XML schema is easier to guard against attacks and malicious input. It is therefore always required to specifiy in the XML Schema wether or not the order in which elements appear matter. This is why an element such as the xsd:sequence is required. Note that this can quickly become a tripwire for your serialization and deserialization.
Your orignal XML could therefore be stated as follows but might be stated differently depending on your exact use case
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
targetNamespace="http://versionschema.org/xmlns/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:vs="http://versionschema.org/xmlns/"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<xsd:element name="VersionSchema" type="vs:VersionSchema"/>
<xsd:complexType name="VersionSchema">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="Field" minOccurs="1" maxOccurs="unbounded"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
The relevant sections would be 3.4 Complex Type Definitions and 2.2.3 Model Group Components. It states that
The XML representation for a complex type definition schema component
is a <complexType> element information item. [...] Content:
(annotation?, (simpleContent | complexContent | (openContent?, (group| all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?), assert*)))
Note that in order to place an <element> into the complex type you either have to use complexContent, a group or modelgroup elements like all, choice or sequence. It is the same for complexContent which cannot contain <element> but only extension which can only contain
(annotation?, openContent?, ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?), assert*))
[...]There are three varieties of model group:
Sequence (the element information items match the particles in
sequential order); Conjunction (the element information items match
the particles, in any order); Disjunction (the element information
items match one or more of the particles). Model Group, a kind of Term
[...] specifies a sequential (sequence), disjunctive (choice) or
conjunctive (all) interpretation of the {particles}. This in turn
determines whether the element information item [children] validated
by the model group must:
(sequence) correspond, in order, to the specified {particles};
(choice) correspond to exactly one of the specified {particles}; (all)
correspond to the specified {particles}. The elements can occur in any
order.
Even if stated slightly confusing in the model group section, a model group can itself only host the following content
(annotation?, (all | choice | sequence)?)
Which pretty much boils down to having to use all, choice and sequence when you would like to use <element>.
all : (annotation?, (element | any | group)*)
choice : (annotation?, (element | group | choice | sequence | any)*)
sequence: (annotation?, (element | group | choice | sequence | any)*)
I have an XML :
<Section>
<Paragraph>
<Text>t1</Text>
<Text>t2</Text>
</Paragraph>
<Paragraph>
<Text>t3</Text>
<Text>t4</Text>
</Paragraph>
</Section>
and I know only element indexes, e.g., /0/1/0 i.e. first Section, second Paragraph, and its first Text. How can I translate '0/1/0' into a valid XPath that returns element where t3 is ?
Note that I don't know element names because they can differ but I only know sequence of indexes as in above example.
Many thanks
For the example given this will work.
/element()[1]/element()[2]/element()[1]/text()
I can't figure out how to write a rule that would solve this requirement :
Let's assume I have this request :
<Request>
<Attributes Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject">
<Content>
<Categories>
<Category name="cat1">
<CategoryValue>A</CategoryValue>
<CategoryValue>B</CategoryValue>
<CategoryValue>C</CategoryValue>
</Category>
<Category name="cat2">
<CategoryValue>B</CategoryValue>
<CategoryValue>E</CategoryValue>
<CategoryValue>F</CategoryValue>
</Category>
</Categories>
</Content>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource">
<Content>
<Categories>
<Category name="cat1">
<CategoryValue>A</CategoryValue>
</Category>
<Category name="cat2">
<CategoryValue>A</CategoryValue>
<CategoryValue>E</CategoryValue>
<CategoryValue>F</CategoryValue>
<CategoryValue>G</CategoryValue>
</Category>
</Categories>
</Content>
</Attributes>
</Request>
I want to write a policy that contains a rule with a Permit effect when for each of the Category elements of the resource, the subject has a Category with the same #name and if both of these Category elements has at least one common CategoryValue.
In this Example above :
Resource has "cat1" with "A" - Subject has "cat1" with one value that is A : Permit
Resource has "cat2" with "A", "E", "F", "G" - Subject has "cat2" with value E (or F) : Permit
Final result of the rule : Permit
My question is not on which functionId I should use, but how can I combine these conditions so that the rule behaves the way I described ? How to compare the GenericValue elements of nodes that has the same #name ?
I think I will have to use the string-at-least-one-member-of function between the values of the subject and resource "cat1", then between the subject and resource "cat2", but the real difficulty is that the PDP has no idea of the #name of the Category elements, so I can't hardcode it directly in the rule and I don't know how to select them in particular to perform the check.
Any idea on this ?
First of all, your request is invalid. You are missing some elements e.g.
ReturnPolicyIdList="true"
CombinedDecision="true"
Secondly, I would recommend you do not use XPath in XACML. It makes your policies hard to write (hence your question), hard to maintain, and hard to read (audit). It defeats the purpose of XACML in a way. Let the PEP do the heavy XML processing and send in attributes with attribute values rather than XML content.
In addition, you cannot control the iteration over the different elements / attribute values in the XML in XACML. I can implement your use case with a specific #name value but I cannot manage to do it over an array of values.
Assuming a single value, you would have to implement a condition as follows:
<xacml3:Rule RuleId="axiomatics-example-xacml30" Effect="Permit" xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17">
<xacml3:Target/>
<xacml3:Condition >
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
<xacml3:AttributeSelector Path="/Categories/Category[#name='cat1']/CategoryValue/text()" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false" Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"/>
<xacml3:AttributeSelector Path="/Categories/Category[#name='cat1']/CategoryValue/text()" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"/>
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
But you cannot really iterate over the different values