I am using IIS 8 and just learning about rewrites as I haven't ever written anything that cared about SEO.
I have the following rules that is working assuming the url looks like this: /survey/abc123/email
<rule name="Survey Rule" stopProcessing="true">
<match url="survey/([_0-9a-z-]+)/([_0-9a-z-]+)" />
<action type="Rewrite" url="survey.htm?var1={R:1}&var2={R:2}" />
</rule>
On the survey.htm page I have code that check for existence of var1 & var2 but in this rewrite if I have the url /survey/abc123 it doesn't obviously hit the Survey Rule. I have tried a couple of <conditions> but could find the right one.
I feel there must be a way to say
If {R:1} exists then var1={R:1} else var1=''
If {R:2} exists then var2={R:2} else var1=''
Ideally some type if loop. Is there any way to do this in a rewrite to that no matter how many / there are after survey, whether 0 or 10 it will always it the survey page?
I have looked at the rewrite map but I am not sure that solves this issue.
Edit
Possible urls that I would like to be rewritten:
/survey/abc123/
/survey.htm?var1=abc123
/survey/abc123/email/
/survey.htm?var1=abc123&var2=email
/survey/abc123/email/bob/
/survey.htm?var1=abc123&var2=email&var3=bob
/survey/abc123/email/bob/someOtherVar
/survey.htm?var1=abc123&var2=email&var3=bob&var4=someOtherVar
/result/1/
/result.htm?var1=1
/result/1/test#example.com
/result.htm?var1=1&var2=test#example.com
I would like the first item after the slash to be the page name and then each item after turned into the "query_string". I hope this makes a little more sense.
Short answer
You can't have exactly what you want with IIS rewrite only. And by what you want, i mean dynamically handling it with a loop.
Long answer
(1) With IIS rewrite only, this is the closest possible solution to your problem:
<rule name="Survey/Result Loop Rule" stopProcessing="true">
<match url="^(survey|result)/([^/]+)/(.*)$" />
<action type="Rewrite" url="/{R:1}/{R:3}?{R:2}={R:2}" appendQueryString="true" />
</rule>
<rule name="Survey/Result Default Rule" stopProcessing="true">
<match url="^(survey|result)/$" />
<action type="Rewrite" url="/{R:1}.htm" appendQueryString="true" />
</rule>
It will simulate a loop as long as the url contains parameters as subfolders, for both /survey/ and /result/. Then, it finally rewrites it to .htm page with query string appened. This is not possible to dynamicly generate query names such as var1 var2 etc by incrementing a number (at least, if a solution exists, it would be very tricky and heavy, because the rewrite engine is not made for this). In this example, both query names and values are the same, such as ?abc123=abc123&email=email.
(2) The cleanest way for this would be to delegate the job to the script:
<rule name="Survey/Result Default Rule" stopProcessing="true">
<match url="^(survey|result)/(.*)$" />
<action type="Rewrite" url="/{R:1}.htm?params={R:2}" />
</rule>
This rule rewrites, for instance, /survey/XXX/YYY/ZZZ/ to /survey.htm?params=XXX/YYY/ZZZ/. Since the job is delegated to the script, your htm files need to implement something like this (in pseudo code):
params = query_get('params');
// remove trailing slash in params if present
parameters = explode("/", query_get('params'))
for (i = 0; i < count(parameters); i++)
var{i+1} = parameters[i]
// var1 = parameters[0]
// var2 = parameters[1]
// var3 = parameters[2]
// and so on...
I think you get the idea.
Related
I am trying to validate the following XML using the Schematron rule.
XML:
<?xml version="1.0" encoding="utf-8"?>
<Biotic><Maul><Number>1</Number>
<Record><Code IDREF="a1"/>
<Detail><ItemID>1</ItemID></Detail>
<Detail><ItemID>3</ItemID></Detail>
</Record>
<Record><Code IDREF="b1"/>
<Detail><ItemID>3</ItemID></Detail>
<Detail><ItemID>4</ItemID></Detail>
</Record>
<Record><Code IDREF="b1"/>
<Detail><ItemID>4</ItemID></Detail>
<Detail><ItemID>6</ItemID></Detail>
</Record>
<Record><Code IDREF="c1"/>
<Detail><ItemID>5</ItemID></Detail>
<Detail><ItemID>5</ItemID></Detail>
</Record>
</Maul></Biotic>
And the check is "ItemID should be unique for the given Code within the given Maul."
So as per requirement Records with Code b1 is not valid because ItemId 4 exists in both records.
Similarly, record C1 is also not valid because c1 have two nodes with itemId 5.
Record a1 is valid, even ItemID 3 exists in the next record but the code is different.
Schematron rule I tried:
<?xml version="1.0" encoding="utf-8" ?><schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<title>Schematron validation rule</title>
<pattern id="P1">
<rule context="Maul/Record" id="R1">
<let name="a" value="//Detail/[./ItemID, ../Code/#IDREF]"/>
<let name="b" value="current()/Detail/[./ItemID, ../Code/#IDREF]"/>
<assert test="count($a[. = $b]) = count($b)">
ItemID should be unique for the given Code within the given Maul.
</assert>
</rule>
</pattern>
</schema>
The two let values seem problematic. They will each return a Detail element (and all of its content including attributes, child elements, and text nodes). I'm not sure what the code inside the predicates [./ItemID, ../Code/#IDREF] is going to, but I think it will return all Detail elements that have either a child ItemID element or a sibling Code element with an #IDREF attribute, regardless of what the values of ItemID or #IDREF are.
I think I would change the rule/#context to ItemID, so the assert would fail once for each ItemID that violates the constraint.
Here are a rule and assert that work correctly:
<?xml version="1.0" encoding="utf-8" ?><schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<title>Schematron validation rule</title>
<pattern id="P1">
<rule context="Maul/Record/Detail/ItemID" id="R1">
<assert test="count(ancestor::Maul/Record[Code/#IDREF = current()/ancestor::Record/Code/#IDREF]/Detail/ItemID[. = current()]) = 1">
ItemID should be unique for the given Code within the given Maul.
</assert>
</rule>
</pattern>
</schema>
The assert test finds, within the ancestor Maul, any Record that has a Code/#IDREF that equals the Code/#IDREF of the Record that the current ItemID is in. At minimum, it will find one Record (the one that the current ItemID is in). Then it looks for any Detail/ItemID within those Records that is equal to the current ItemID. It will find at least one (the current ItemID). The count function counts how many ItemIDs are found. If more than one is found, the assert fails.
Thanks for the reference to https://www.liquid-technologies.com/online-schematron-validator! I wasn't aware of that tool.
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 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
I'm trying to write a Schematron rule to perform the following test...
If no li under root contains "abc" and root contains title, "def" then report.
The problem that I'm having is that I am getting many false positives. Here is my current XPath...
<rule context="li">
<assert test="not(contains(text(),'abc')) and ancestor::root/descendant::title = 'def'">Report this.</assert>
</rule>
My output ends up reporting on each li that does not contain "abc" which I understand since it is testing every li and reporting.
However, I don't know how to write the XPath so that I can test if any li contains "abc".
Thanks!
The problem, as you hinted at, is that you've expressed this in Schematron as a rule that applies to each li element; whereas the rule you've described in English is one that applies to each root element.
So you could express it as
<rule context="root">
<assert test=".//li[contains(text(),'abc')] or
not(.//title = 'def')">Report this.</assert>
</rule>
Note that I've flipped the sense of the test, to match your English description
If no li under root contains "abc" and root contains title, "def" then report.
Since you're using an <assert> element, you assert the opposite of what you want to report. It might make more sense to use a <report> element:
<rule context="root">
<report test="not(.//li[contains(text(),'abc')]) and
.//title = 'def'">Report this.</report>
</rule>
Please explain all the attributes of Magento block tag
<block type="catalog/product_featured" name="product_featured"
as="product_featured"
template="catalog/product/featured.phtml"></block>
<block type="catalog/product_featured" name="product_featured" template="catalog/product/featured.phtml">
<action method="setLimit"><limit>2</limit></action>
</block>
also why do we need two times the block tag
type = PHP file the template will look for the methods.. Here it is Mage_Catalog_Block_Product_Featured.php
name = Name of the block. It should be unique in the page.
as = Alias. Smaller form of name. It should be unique in it's parent block.
template = The template file (View) this block is attached to. You can call methods from block type inside this by using $this.. e.g. $this->getName()
name vs. as example:
<reference name="left">
<block type="block/type1" name="first_block" template="template1.phtml">
<block type="abc/abc" name="abc" as="common" template="abc.phtml"/>
</block>
<block type="block/type2" name="second_block" template="template2.phtml">
<block type="xyz/xyz" name="xyz" as="common" template="xyz.phtml"/>
</block>
</reference>
So, you can now call block name abc from first_block AND xyz from second_block as $this->getChildHtml('common');, but see both the blocks called will be different as per their calling parent.