validate XML with Schematron - schematron

I have the following xml and I would like to unwrap the ph element which is greater than 2.
Input:(xml)
<ul>
<li>
<ph>123</ph>
</li>
<li>
<ph>456</ph>
</li>
<li>
<ph>abc</ph>
</li>
<li>
<ph>xyz</ph>
</li>
</ul>
O/P:
<ul>
<li>
<ph>123</ph>
</li>
<li>
<ph>456</ph>
</li>
<li>
abc
</li>
<li>
xyz
</li>
</ul>
and the below code doesn't work to get the desired output
<sch:pattern>
<sch:rule context="*/ph" role="error">
<sch:assert test="not(node()>2)" sqf:fix="unwrap"><sch:name/> element not
allowed</sch:assert>
<sqf:fix id="unwrap">
<sqf:description>
<sqf:title>unwrap <sch:name/> element</sqf:title>
</sqf:description>
<sqf:replace select="node()"></sqf:replace>
</sqf:fix>
</sch:rule>
Regards,
Shil

Ok, assuming that you mean with "greater than 2" the index of the li elements, you could do the following:
Set the context to li[position() gt 2] to get only the li elements with a position greater than 2.
Check if there is a ph element.
Make the unwrap sqf:fix starting from the li element.
The solution would look like this:
<sch:rule context="li[position() gt 2]">
<sch:report test="ph" sqf:fix="unwrap">ph element not allowed.</sch:report>
<sqf:fix id="unwrap">
<sqf:description>
<sqf:title>Unwrap ph element.</sqf:title>
</sqf:description>
<sqf:replace match="ph" select="node()"/>
</sqf:fix>
</sch:rule>
Another way would be, to set the context to ul. In this case you would only get one error message and the QuickFix could do the unwrap at once.

<sch:pattern>
<sch:rule context="li[position() > 2]">
<xsl:variable name="offendingph">
<xsl:for-each select="child::ph">
<xsl:value-of select="node()"/>
</xsl:for-each>
</xsl:variable>
<sch:report test="child::ph" sqf:fix="unwrap">ph element not allowed.</sch:report>
<sqf:fix id="unwrap">
<sqf:description>
<sqf:title>Unwrap ph element.</sqf:title>
</sqf:description>
<sqf:replace match="ph" select="$offendingph"/>
</sqf:fix>
</sch:rule>
</sch:pattern>

Related

I need to be able to select a distinct dynamic xpath

I need to select a distinct dynamic xpath in selenium between 2 pieces of xml that are identical (Dresses). I need to create the dynamic xpath for the second value which clicks the button itself. I have tried: //a[#title = 'Dresses'][#class = 'sf-with-ul'] which selects both the image and the button.
Here is the code:
<li class="sfHoverForce" xpath="1">
Dresses
<ul style="display: none;">
<li>Casual Dresses</li>
<li>Evening Dresses</li>
<li>Summer Dresses</li>
</ul>
</li>
<li id="category-thumbnail" xpath="1">
<div><img src="http://automationpractice.com/img/c/3-0_thumb.jpg" alt="Women" title="Women" class="imgm"></div>
<div><img src="http://automationpractice.com/img/c/3-1_thumb.jpg" alt="Women" title="Women" class="imgm"></div>
</li>
<li class="sfHoverForce" xpath="1">
Dresses
<ul class="submenu-container clearfix first-in-line-xs" style="display: none;">
<li>Casual Dresses</li>
<li>Evening Dresses</li>
<li>Summer Dresses</li>
</ul>
</li>
The only difference between the two nodes are the UL tag - class value. try this xpath to select the second node with anchor,
//ul[contains(#class,'submenu-container')]/preceding-sibling::a[#title='Dresses']
With the HTML you posted, this XPath will work
//a[#title='Dresses'][./following-sibling::ul[contains(#class,'submenu-container')]]
^ find an A tag with a specific title
^ the A tag should have a sibling UL
^ and that UL contains a specific class
You could try this:
//li[a[#title='Dresses']][2]/a
This will get the 2nd a element with title ‘Dresses’. If you want the first element, change the index from 2 to 1.

Neither ng-hide nor ng-show change the visibility of the element

I began to use AngularJS, and I decided to make a list appear when I click on a button.
My code is rather simple, but it doesn't work, and I don't understand why:
<div ng-app="myGame" ng-controller="gameCtrl">
<h1>{{showLevels}}</h1>
<p ng-show="showLevels">
<ul>
<li>Level 1</li>
<li>Level 2</li>
<li>Level 3</li>
</ul>
</p>
<button ng-click="toggle()">Begin Game !</button>
</div>
And, in the JavaScript file:
var app = angular.module("myGame", []);
app.controller("gameCtrl", function ($scope) {
$scope.showLevels = false;
$scope.toggle = function () {
$scope.showLevels = !$scope.showLevels;
};
});
The levels are always shown, whether I use the ngShow or ngHide directive, despite the fact that $scope.showLevels is toggled, as I can see next to the title.
Where does this problem come from?
The paragraph element <p> can only accept phrasing content, and the unordered list element <ul> is not such a content.
Therefore, your browser translates your code into another one making more sense for it, by taking the <ul> out of the <p>. Your HTML is in fact:
<p ng-show="showLevels"></p>
<ul>
<li>Level 1</li>
<li>Level 2</li>
<li>Level 3</li>
</ul>
That's why your list is always visible, no matter the content of the $scope.showLevels variable. The solution is to use another element, a document division element <div> for instance, or to remove this intermediate element completely:
<ul ng-show="showLevels">
<li>Level 1</li>
<li>Level 2</li>
<li>Level 3</li>
</ul>

ng-repeat - content to show if array is empty or null

I've a deep nested ng-repeat lists, and only in the last loop I've to display alternate content if list was empty. I'm new to angular, saw some posts online please help me where can I use content if list is empty. The ng-repeat=sessions in day could be empty.
<ul class="day">
<li ng-repeat="sessions in day">
<ul class="table-view">
<li class="table-view-cell" ng-repeat="(heading, session) in sessions">
<span class="group">{{heading}}</span>
<ul class="cell">
<li class="cell-content" ng-repeat="val in session" ng-click="getSession(val.id)">
<div class="time" style="background-color:#{{val.color}}">
<span>{{val.start | date:"h:mma"}}</span>
<span>to</span>
<span>{{val.end | date:"h:mma"}}</span>
</div>
<div class="session" ng-class-odd="'odd'" ng-class-even="'even'">
<span class="name">{{val.name}}</span>
<span class="room">Room: {{val.room}}</span>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
1). CSS approach. I usually use pure CSS approach in such cases. With this markup (stripped extra-html):
<ul class="day">
<li ng-repeat="sessions in day">
...
</li>
<li class="no-sessions">
No sessions on this day.
</li>
</ul>
and CSS rules to hide .no-sessions li by default and make it visible only if there are no previous li tags:
li.no-sessions {
display: block;
}
li + li.no-sessions {
display: none;
}
So when sessions array is empty, there will be no li rendered and only no-sessions one will be visible. And if will hide as soon as there is at least one session on this day.
Demo: http://plnkr.co/edit/KqM9hfgTTiPlkdmEevDv?p=preview
2). ngIf approach. Of course you can use ngIf/ngShow directives for show no-records element when sessions array is empty:
<li ng-if="!day.length">
No sessions on this day.
</li>
I think this would work for your case:
<li ng-hide="day.length > 0">
No sessions on this day.
</li>
No extra CSS needed. Assumes day is an array.
http://plnkr.co/edit/WgDviOKjHKS1Vt5A5qrW
I would recommend handling that in your controller. Keeping your logic in the controller and javasript makes debugging easier and more manageable. I can think of 2 approaches: using ng-show/ng-hide or a condition for your day variable when its empty.
Option 1
ng-show/ng-hide approach:
$scope.isDayEmpty = function(){
return $scope.day.length > 0 ? false : true;
}
html:
<ul class="day">
<li ng-repeat="sessions in day" ng-hide="isDayEmpty">
...
</li>
<li ng-show="isDayEmpty">
No Sessions this Day
</li>
</ul>
Option 2:
ng-repeat approach
if($scope.day.length == 0){
$scope.day.push("No Sessions this Day");
}
This should get you essentially the same result. The first approach would make your CSS styling easier assuming you want to do something different in that case.
The second approach can vary in style depending on your code but thats an example of how you can do it. I don't know your javascript so I can't be more specific to your scenario.

Hide parent if child is empty

I want to hide the parent li if child li is empty. Here is the jsfiddle link where I want to hide the parent li label TWO.
<ul id='ListNav'>
<li ng-repeat='mainList in lists.list' ng-hide='subList.length<0' >
<a>{{mainList.label}}</a>
<ul>
<li ng-repeat='subList in mainList.subList'>{{subList.label}}</li>
</ul>
</li>
</ul>
To solve this problem just change:
<li ng-repeat='mainList in lists.list' ng-hide='subList.length<0' >
To
<li ng-repeat='mainList in lists.list' ng-show="mainList.subList.length>0" >
Demo
you cant use subList at that level try changing it for mainList.subList
<ul id='ListNav'>
<li ng-repeat='mainList in lists.list' ng-hide='mainList.subList.length==0'> <a>{{mainList.label}}</a>
<ul>
<li ng-repeat='subList in mainList.subList'>{{subList.label}}</li>
</ul>
</li>
</ul>
http://jsfiddle.net/nepfw2qf/7/

jQuery live sibling-selector not working

I have this CSS selector, which just won't bind .live(), but works perfectly with .bind():
$('.treeView li ~ :has("ul")').prev('li')
I've read somewhere, that using the .prev() and .next() could be troublesome coupled with .live(), so I wanted to create an pure CSS selector (or ANYTHING that works with .live()!) to do the job - but I just can't figure it out!
Here's what I want to do:
Select all li-elements, which is followed by an li containing an ul.
Here's an HTML markup example, I want to select the ones where the comment says "selected"
<div class="treeView" id="processSegmentsTree">
<ul>
<li>Ostetanke</li> //selected
<li>
<ul>
<li>Tank 1</li>
<li>Tank 2</li>
</ul>
</li>
<li>Presse</li> //selected
<li>
<ul>
<li>Sub-leaf 1</li>
<li>Sub-leaf 2</li> //selected
<li>
<ul>
<li>test</li>
<li>test</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
Any help is much appreciated, since this is a bit of a thorn in my eye :(
There is no such Selector to accomplish this task.
What I highly recommend you to do is to add ANYTHING as a flag to use when selecting your desired elements.
add attribute, wrapper, ANYTHING YOU WANT, then the task will be as easy as it should be.
This may work: // not css selector
$(".treeView li:has('ul')").prev();

Resources