-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
XML schema validation #1
Comments
A sample of what it could look like can be found here: It was generated based on all of MarkupKit's sample XML content. Clearly just a starting point as it would need some generalization & tweaking. |
I looked into something like this myself a while back. My plan was to generate an XSD file by using the Objective-C runtime APIs to enumerate all of the classes that extend https://developer.apple.com/documentation/objectivec/objective_c_runtime?language=objc I was originally hoping to do this in a Mac command-line tool, but it doesn't seem like it's possible to load iOS simulator binaries in macOS, even though they are compiled for x86. However, it should be possible to do in iOS. It's a little clunky, but the generated document could probably be retrieved by navigating to the Documents directory for the simulator. |
Ah yes, I remember looking into this briefly too. I'd prefer this approach, as opposed to cobbling together the XSD by hand 🤔. Thanks for the pointer. |
It's been a while since I worked with XML Schema, but I believe it is possible to define hierarchical relationships. So there could be definitions for Although I can see how it would be useful, I hadn't considered restricting sub-elements to specific types (such as I think it should be pretty easy to dynamically generate a schema that can do this (plus the reserved attributes like "id", "style", "class", and "on..."). However, it will be more difficult to automatically infer valid sub-elements. In fact, it may not even be possible to know in advance the complete set of valid elements, since an application may define custom view types or make use of additional 3rd-party frameworks. Further, some existing classes support untyped sub-elements like Similarly, it may be difficult or impossible to generate a schema that can validate attribute values. The Objective-C runtime knows about property names, but not much about property types. For example, enum types are not available at runtime - they are reported as int/long, I think. Since enum values are specified as strings in MarkupKit, we wouldn't want to restrict the corresponding attribute types to numerics. Finally, I don't think XSD handles processing instructions. So we wouldn't be able to validate things like So, although I didn't get too far along with it, my approach was simply going to validate property names for known element types. Ideally, unknown elements would be ignored rather than flagged as errors. Not sure if this is possible with xmllint or not. |
It's been ages for me too, but I think even class inheritance can be expressed.
My example XSD was generated by the Xmplify app, which attempts to infer these types of relationships automatically. If used at all, I'd only restrict a very strict subset (like the pair you mentioned).
Perhaps it would be enough to just validate the mere presence/applicability of attributes, and omit value validation altogether at first.
I think this can be achieved with I'll play around a bit, could be a dead end, but it's worth a shot, I think. |
Yeah, that's exactly what I meant. You could define a an element type hierarchy that mirrors the
Agreed - that's exactly what I was thinking.
Based on some limited research, I think you are right.
It's definitely worth a shot (especially if you are volunteering to do it)! ;-) It's something I would definitely use, and I imagine a lot of other developers would find it useful as well. |
Yes! MarkupKit need this kind of tooling for it to become mainstream 👍 . |
Made some initial headway here! I looked into how I ran across an alternate XML schema language called RelaxNG, which is also supported by The resulting POC can be found in the Schemas/ directory. It's quite bare, but it achieves the following validation: (1) LMSpacer (and any other we want to define) gets validated, if used. In this instance, it's verified to be an empty element, and fails if it has text content, e.g. (2) The root element is allowed to have any name, which supports our 2 main use cases:
(3) The root element is allowed to have any attribute for now. Other, undefined elements and attributes also pass through, allowing for user-defined markup elements. Albeit limited, this POC proves RelaxNG schemas are flexible enough for our use case. Next, I will take a jab at building this schema dynamically using NSXML in an iOS app with MarkupKit loaded. |
Nice work! I had forgotten about RelaxNG. Just curious - do you know if it supports type hierarchies? If not, maybe something even simpler like DTD could be an option. On the other hand, I'm not sure how flexible DTD would be with wildcard types. Just something to think about. |
No, RelaxNG doesn't support inheritance per se. However, as I understand it, element types' properties can be composed (a bit like mixins [my interpretation]). For instance, I think it should be possible to create <define name="LMBoxView" combine="interleave">
<zeroOrMore>
<attribute name="spacing"/>
</zeroOrMore>
</define>
<define name="LMRowView" combine="interleave">
<ref name="LMBoxView"/>
<zeroOrMore>
<attribute name="alignToBaseline"/>
</zeroOrMore>
</define>
<define name="LMColumnView" combine="interleave">
<ref name="LMBoxView"/>
<zeroOrMore>
<attribute name="alignToGrid"/>
</zeroOrMore>
</define> It's probably a little rough, but if it holds true, this mechanism could be used to compose the various types in MarkupKit without needing true inheritance.
AFAIK DTD doesn't support the "anyName" scenario like RelaxNG does. It has an |
Makes sense. I just looked into DTD a bit - definitely no support for inheritance there, so there would be some attribute duplication. However, it would probably be primarily limited to DTD's lack of support for undefined elements is definitely a disadvantage, but if it were possible to easily generate a DTD for a given framework (or app bundle), then it might not be such a big deal. It could be viewed as analogous to importing a module - if you don't import the module, your code won't compile. For that matter, the same argument could be applied to XSDs. And we know that XSDs do support inheritance. But again, just thinking out loud...not really sure what the best approach would be. |
Just a thought - using the Objective-C runtime, it should be possible to dynamically determine all public |
Great input! In any case, I'll get started on the runtime component, so we have an idea of what it takes to extract the model we need. Interesting stuff 🙂. |
Tweaked the schema some more. It should now allow a Also, I have the basic schema generation code, using the ObjC runtime. I just need to clean it up a bit so I can push it. I was able to extract all UIKit properties (down to UIView/UIControl) and emulate inheritance in the schema using |
Sounds good - can't wait to see it. |
I was able to push the first iteration of the schema generation code. It can be found in the /Tools directory. Here's a quick overview of its current capabilities. It generates a RelaxNG schema that:Declares the various MarkupKit element types along with their legal attribute names
Container elements (e.g. LMBoxView descendants) can contain
Allows for a
Current limitationsAttribute validation
Unknown elements
Next tasksIn order to achieve a schema that would be generally useful, without needing to resort to app-specific schema generation, I think the following things still need to be done Attribute validation
Unknown elements
Support more MarkupKit elements
Set up more elaborate test cases
Sample schemaHere's a printout of the schema current generated by <?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
<!-- Root of the document. -->
<start>
<ref name="RootElement"/>
</start>
<!--
The root element can only be one of the known MarkupKit elements,
or a <root> element.
-->
<define name="RootElement">
<choice>
<!-- [GENERATED] References to all known MarkupKit element types. -->
<ref name="LMSpacer"/>
<ref name="LMLinearGradientView"/>
<ref name="LMRadialGradientView"/>
<ref name="LMPlayerView"/>
<ref name="LMColumnView"/>
<ref name="LMRowView"/>
<ref name="LMLayerView"/>
<ref name="LMAnchorView"/>
<ref name="LMScrollView"/>
<ref name="LMPageView"/>
<ref name="LMPickerView"/>
<!--
The <root> element can have any attribute (by necessity, as
the actual type is only knowable at runtime). Its children
must be MarkupKitElements.
-->
<element name="root">
<zeroOrMore>
<ref name="any_attribute"/>
</zeroOrMore>
<zeroOrMore>
<ref name="MarkupKitElements"/>
</zeroOrMore>
</element>
</choice>
</define>
<!--
//////////////////////////////////////////////////////////////////////
// MarkupKit Types //
//////////////////////////////////////////////////////////////////////
-->
<!-- References all known MarkupKit element types.-->
<define name="MarkupKitElements">
<!-- [GENERATED] -->
<zeroOrMore>
<ref name="LMSpacer"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMLinearGradientView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMRadialGradientView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMPlayerView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMColumnView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMRowView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMLayerView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMAnchorView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMScrollView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMPageView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="LMPickerView"/>
</zeroOrMore>
<zeroOrMore>
<ref name="any_element"/>
</zeroOrMore>
</define>
<!-- [GENERATED] -->
<define name="LMSpacer">
<element name="LMSpacer">
<ref name="UIView"/>
<empty/>
</element>
</define>
<define name="LMLinearGradientView">
<element name="LMLinearGradientView">
<zeroOrMore>
<attribute name="startX"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="startY"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="startPoint"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="endX"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="endY"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="endPoint"/>
</zeroOrMore>
<ref name="LMGradientView"/>
<ref name="UIView"/>
<empty/>
</element>
</define>
<define name="LMRadialGradientView">
<element name="LMRadialGradientView">
<zeroOrMore>
<attribute name="centerX"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="centerY"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="centerPoint"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="radius"/>
</zeroOrMore>
<ref name="LMGradientView"/>
<ref name="UIView"/>
<empty/>
</element>
</define>
<define name="LMPlayerView">
<element name="LMPlayerView">
<ref name="UIView"/>
<empty/>
</element>
</define>
<define name="LMColumnView">
<element name="LMColumnView">
<zeroOrMore>
<attribute name="alignToGrid"/>
</zeroOrMore>
<ref name="LMBoxView"/>
<ref name="LMLayoutView"/>
<ref name="UIView"/>
<zeroOrMore>
<ref name="MarkupKitElements"/>
</zeroOrMore>
</element>
</define>
<define name="LMRowView">
<element name="LMRowView">
<zeroOrMore>
<attribute name="alignToBaseline"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="baseline"/>
</zeroOrMore>
<ref name="LMBoxView"/>
<ref name="LMLayoutView"/>
<ref name="UIView"/>
<zeroOrMore>
<ref name="MarkupKitElements"/>
</zeroOrMore>
</element>
</define>
<define name="LMLayerView">
<element name="LMLayerView">
<ref name="LMLayoutView"/>
<ref name="UIView"/>
<zeroOrMore>
<ref name="MarkupKitElements"/>
</zeroOrMore>
</element>
</define>
<define name="LMAnchorView">
<element name="LMAnchorView">
<ref name="LMLayoutView"/>
<ref name="UIView"/>
<zeroOrMore>
<ref name="MarkupKitElements"/>
</zeroOrMore>
</element>
</define>
<define name="LMScrollView">
<element name="LMScrollView">
<zeroOrMore>
<attribute name="contentView"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="fitToWidth"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="fitToHeight"/>
</zeroOrMore>
<ref name="UIScrollView"/>
<ref name="UIView"/>
<zeroOrMore>
<ref name="MarkupKitElements"/>
</zeroOrMore>
</element>
</define>
<define name="LMPageView">
<element name="LMPageView">
<zeroOrMore>
<attribute name="pages"/>
</zeroOrMore>
<ref name="UIScrollView"/>
<ref name="UIView"/>
<zeroOrMore>
<ref name="MarkupKitElements"/>
</zeroOrMore>
</element>
</define>
<define name="LMPickerView">
<element name="LMPickerView">
<ref name="UIPickerView"/>
<ref name="UIView"/>
<zeroOrMore>
<ref name="MarkupKitElements"/>
</zeroOrMore>
</element>
</define>
<!--
//////////////////////////////////////////////////////////////////////
// UIKit Traits //
//////////////////////////////////////////////////////////////////////
-->
<!-- [GENERATED] -->
<define name="UIView">
<zeroOrMore>
<attribute name="width"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="minimumWidth"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="maximumWidth"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="height"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="minimumHeight"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="maximumHeight"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="aspectRatio"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="weight"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="anchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="horizontalContentCompressionResistancePriority"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="horizontalContentHuggingPriority"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="verticalContentCompressionResistancePriority"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="verticalContentHuggingPriority"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="layoutMarginTop"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="layoutMarginLeft"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="layoutMarginBottom"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="layoutMarginRight"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="skipsSubviewEnumeration"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="viewTraversalMark"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="viewDelegate"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="monitorsSubtree"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="backgroundColorSystemColorName"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="currentScreenScale"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="maskView"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="hash"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="superclass"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="description"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="debugDescription"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="gesturesEnabled"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="deliversTouchesForGesturesToSuperview"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="deliversButtonsForGesturesToSuperview"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="leadingAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="trailingAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="leftAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="rightAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="topAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="bottomAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="widthAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="heightAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="centerXAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="centerYAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="firstBaselineAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="lastBaselineAnchor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="contentSizeNotificationToken"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="layoutMarginsGuide"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="readableContentGuide"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="previewingSegueTemplateStorage"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="interactionTintColor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="wantsDeepColorDrawing"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="userInteractionEnabled"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="tag"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="layer"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="canBecomeFocused"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="focused"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="semanticContentAttribute"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="effectiveUserInterfaceLayoutDirection"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="traitCollection"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="preferredFocusEnvironments"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="preferredFocusedView"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="preferredFocusMovementStyle"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="linearFocusMovementSequences"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="focusedView"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="center"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="bounds"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="transform"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="collisionBoundsType"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="collisionBoundingPath"/>
</zeroOrMore>
</define>
<define name="LMGradientView">
<zeroOrMore>
<attribute name="colors"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="locations"/>
</zeroOrMore>
</define>
<define name="LMBoxView">
<zeroOrMore>
<attribute name="horizontalAlignment"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="verticalAlignment"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="spacing"/>
</zeroOrMore>
</define>
<define name="LMLayoutView">
<zeroOrMore>
<attribute name="arrangedSubviews"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="layoutMarginsRelativeArrangement"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="topSpacing"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="bottomSpacing"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="leadingSpacing"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="trailingSpacing"/>
</zeroOrMore>
</define>
<define name="UIScrollView">
<zeroOrMore>
<attribute name="contentInsetTop"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="contentInsetLeft"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="contentInsetBottom"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="contentInsetRight"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="currentPage"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="adjustsTargetsOnContentOffsetChanges"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="firstResponderKeyboardAvoidanceEnabled"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="programmaticScrollEnabled"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="scrollingToTop"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="isAnimatingScroll"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="isVerticalBouncing"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="isHorizontalBouncing"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="isAnimatingZoom"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="zoomAnchorPoint"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="scrollTestParameters"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="minimumContentOffset"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="maximumContentOffset"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="forwardsTouchesUpResponderChain"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="focusFastScrolling"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="attemptingToEndFocusFastScrolling"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="showingFocusFastScrollingPreview"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="contentOffset"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="contentSize"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="contentInset"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="directionalLockEnabled"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="bounces"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="alwaysBounceVertical"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="alwaysBounceHorizontal"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="pagingEnabled"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="scrollEnabled"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="showsHorizontalScrollIndicator"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="showsVerticalScrollIndicator"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="scrollIndicatorInsets"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="indicatorStyle"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="decelerationRate"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="indexDisplayMode"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="tracking"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="dragging"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="decelerating"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="delaysContentTouches"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="canCancelContentTouches"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="minimumZoomScale"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="maximumZoomScale"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="zoomScale"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="bouncesZoom"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="zooming"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="zoomBouncing"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="scrollsToTop"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="panGestureRecognizer"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="pinchGestureRecognizer"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="directionalPressGestureRecognizer"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="keyboardDismissMode"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="refreshControl"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="touchDelayForScrollDetection"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="scrollHysteresis"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="canScrollX"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="canScrollY"/>
</zeroOrMore>
</define>
<define name="UIPickerView">
<zeroOrMore>
<attribute name="magnifierLineColor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="enabled"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="retargetBehavior"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="usesModernStyle"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="highlightColor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="textColor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="textShadowColor"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="showsSelectionIndicator"/>
</zeroOrMore>
<zeroOrMore>
<attribute name="numberOfComponents"/>
</zeroOrMore>
</define>
<!--
//////////////////////////////////////////////////////////////////////
// Wildcard types //
//////////////////////////////////////////////////////////////////////
-->
<!--Any individual element. -->
<define name="any_element">
<element>
<anyName>
<!--
References all known MarkupKit element type names here.
This mechanism allows unknown types to be used, while still
type checking MarkupKit elements.
-->
<except>
<!-- [GENERATED] -->
<name>LMSpacer</name>
<name>LMLinearGradientView</name>
<name>LMRadialGradientView</name>
<name>LMPlayerView</name>
<name>LMColumnView</name>
<name>LMRowView</name>
<name>LMLayerView</name>
<name>LMAnchorView</name>
<name>LMScrollView</name>
<name>LMPageView</name>
<name>LMPickerView</name>
</except>
</anyName>
<zeroOrMore>
<ref name="any_attribute"/>
</zeroOrMore>
<zeroOrMore>
<ref name="any_content"/>
</zeroOrMore>
</element>
</define>
<!-- Any contiguous collection of elements. -->
<define name="any_content">
<interleave>
<zeroOrMore>
<ref name="any_element"/>
</zeroOrMore>
<text/>
</interleave>
</define>
<!-- Any attribute. -->
<define name="any_attribute">
<attribute>
<anyName/>
</attribute>
</define>
</grammar>
|
As I recall, the runtime provides only very limited type information (basically just numeric primitives - no classes or enumerated types). That's why I was suggesting that we might only be able to validate attribute names, vs. both names and values. But I could be wrong.
That's an interesting idea, but how would it work for untyped elements such as I agree that app-specific schema generation would not be ideal. I'd much rather include a complete schema with each MarkupKit release, if possible. I'd guess that a schema that includes all UIKit and MarkupKit types would be sufficient for most use cases. From my experience, custom views are not that common (except for table/collection view cells, but those are typically instantiated programmatically, not declaratively). What do you think? |
I did a quick print-out of the property types available for the current schema (https://github.com/jarrroo/MarkupKitLint/blob/master/Tools/mkgen/Sources/Util/MKLInspector.m#L50):
As you can see, the list contains various primitive, struct and even object types. I think we can do a pretty good job of value validation. Some property types are
I think we can explicitly exclude elements like
That's what I'll do. It'll cover 90% of the cases, I agree. |
Create or generate a basic schema which can be used to validate MarkupKit XML files. It should have knowledge of all the standard components and attributes, while still allowing custom (unknown) types.
The text was updated successfully, but these errors were encountered: