MaxLength restriction for MultiLineText field in SDL Tridion 2011 - tridion

My schema source looks like follows:
<xsd:schema xmlns="uuid:b8fd4596-56ec-4718-ad00-bf2a70a148c2" xmlns:tcmi="http://www.tridion.com/ContentManager/5.0/Instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="uuid:b8fd4596-56ec-4718-ad00-bf2a70a148c2">
<xsd:import namespace="http://www.tridion.com/ContentManager/5.0/Instance"></xsd:import>
<xsd:annotation>
<xsd:appinfo>
<tcm:Labels xmlns:tcm="http://www.tridion.com/ContentManager/5.0">
<tcm:Label ElementName="description" Metadata="false">Description</tcm:Label>
<tcm:Label ElementName="multiline" Metadata="false">Multiline</tcm:Label>
</tcm:Labels>
</xsd:appinfo>
</xsd:annotation>
<xsd:element name="Blog">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="description" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:appinfo>
<tcm:ExtensionXml xmlns:tcm="http://www.tridion.com/ContentManager/5.0"></tcm:ExtensionXml>
</xsd:appinfo>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:normalizedString">
<xsd:minLength value="1"></xsd:minLength>
<xsd:maxLength value="20"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="multiline" minOccurs="0" maxOccurs="1" type="tcmi:MultiLineText">
<xsd:annotation>
<xsd:appinfo>
<tcm:ExtensionXml xmlns:tcm="http://www.tridion.com/ContentManager/5.0">
<configuration xmlns="http://www.sdltridion.com/2011/SiteEdit">
<field>
<editable>true</editable>
</field>
</configuration>
</tcm:ExtensionXml>
<tcm:Size xmlns:tcm="http://www.tridion.com/ContentManager/5.0">5</tcm:Size>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element></xsd:schema>
I'm able to use the maxlength and minLength restrictions on a "xsd:normalizedString" type field, but I'm not able to use the same restrictions for the "tcmi:MultiLineText" type. Anyone knows how can I use them on that type of field?
In case it's not possible to use that restrictions in that field, I know there are other ways of validating content on save in Tridion (as Nuno and Robert explained in http://nunolinhares.blogspot.com.es/2012/07/validating-content-on-save-part-1-of.html and http://www.curlette.com/?p=913, thanks for that job!) but I would like to find a solution avoiding the use of events. Any other ideas?

Unfortunately this can not be done on multi-line fields. This holds true for both RTF enabled fields and multi-line plain text fields.
This is by design (and actually makes a lot of sense), as trying to limit text is normally to do with the amount of space used by the text, and these fields support line breaks (and other formatting in the case of RTF enabled fields) so the string length has little to do with the space used by the text.
If your field is an RTF field, you could write a "Truncate" XSLT to apply to the text. Otherwise you will need to use one of the solutions you have referenced above.
Alternatively you might consider truncating the text with your output templates if it is too long.

Related

How to set weight for geo-elem-pair-query in MarkLogic structure query?

I'm trying to rewrite the following cts query using XML structure query:
cts:element-pair-geospatial-query(
fn:QName("http://www.example.com/2009/foo","wgs84"),
fn:QName("http://www.example.com/2009/foo","latitude"),
fn:QName("http://www.example.com/2009/foo","longitude"),
cts:circle("#12 53.411541,-2.9900994"),
("coordinate-system=wgs84","score-function=reciprocal","slope-factor=4"),
32
)
I converted it into:
<geo-elem-pair-query>
<parent ns="http://www.example.com/2009/foo" name="wgs84" />
<lat ns="http://www.example.com/2009/foo" name="latitude" />
<lon ns="http://www.example.com/2009/foo" name="longitude" />
<fragment-scope>documents</fragment-scope>
<geo-option>coordinate-system=wgs84</geo-option>
<geo-option>score-function=reciprocal</geo-option>
<geo-option>slope-factor=4</geo-option>
<circle>
<radius>12.0</radius>
<point>
<latitude>53.411541</latitude>
<longitude>-2.9900994</longitude>
</point>
</circle>
</geo-elem-pair-query>
Unfortunately, I don't know how to add weight into <geo-elem-pair-query>. Accordingly to MarkLogic documentation it seems to be unsupported (but cts equivalent supports it). I've tried to add <weight>32.0</weight> but it doesn't work.
Do you know if there is a way to add weight to geo-elem-pair-query structure query?

R XML parsing to data-frame

I have various XML files with information as shown below. Im having difficulty parsing this variable XML format into a dataframe that can handle both differing numbers of metrics and duplicated properties tags.
<ProducedFruits>
<FruitType>
<FruitName>Apple</FruitName>
<FruitMetrics>
<Properties Sugars="27.51" Rate="5.03" />
<Properties Sugars="219.39" Rate="12.19" />
<Properties Sugars="266.34" Rate="75.9" />
</FruitMetrics>
</FruitType>
<FruitType>
<FruitName>Lime</FruitName>
<FruitMetrics>
<Properties Sugars="1884.2" Rate="5" />
<Properties Sugars="1884.2" Rate="98.3" />
</FruitMetrics>
</FruitType>
<FruitType>
<FruitName>Lemon</FruitName>
<FruitMetrics>
<Properties Sugars="1064.77" Rate="5" />
<Properties Sugars="1064.77" Rate="56" />
</FruitMetrics>
</FruitType>
<FruitType>
<FruitName>Banana</FruitName>
<FruitMetrics>
<Properties Sugars="113" Rate="12" />
<Properties Sugars="113" Rate="79" />
</FruitMetrics>
</FruitType>
</ProducedFruits>
Each file may be somewhat different, so ideally i would to create something that can handle the inconsistent number of values that also preserves the fruitname and creates a dataframe like the one at the bottom.
enter image description here
To pass your xml into R as a dataframe you can use the XML package (https://cran.r-project.org/web/packages/XML/), e.g. data <- XML::xmlParse("doc.xml") then bind lists together with xml_data <- XML::xmlToList(data) then xml_df <- as.data.frame(xml_data) (per: How to parse XML to R data frame)

Drillthrough to underlying text data in icCube?

How to set-up a model in icCube to allow to drill down to the details, when details contain text fields?
The idea is to get a list, with column names containing the text fields (in combination with amount fields). Just like a simple SQL statement would give.
I have tried the following:
a) added a technical dimension that is linked to the rows (via rownumber) and added MIN Aggregation for the text fields. With the idea to use these when a DRILLTHROUGH MDX statement is invoked. The DRILLTHROUGH function works, but does not give the values next to each other for the measures. Result is like:
b) added each unique line a line number and loaded the line number as lowest detail in one of the dimensions. Added attributes for these text and date items for the "drillthrough" columns. Next, added calculated measures to get the property for these attributes. The drillthrough is now effectively a drillby to the lowest details. It works, but this is not nice as it blows up my dimension.
c) tried to use the widget data source SQL, but it is not available for text files, and it does not work for MSAccess files (too slow).
The preferable solution should works in the dashboards and in any XMLA/REST API interface.
Enclosed this example
the schema file
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schemaFactory revisionNumber="7">
<schemaDefinition name="drilltrhough-text" description="" group="Issues" loadOnStartup="false">
<activateIncrementalLoad>false</activateIncrementalLoad>
<useUnknownMembersInFacts>true</useUnknownMembersInFacts>
<autoCleanUpTableColumns>false</autoCleanUpTableColumns>
<useFactPartitioning>false</useFactPartitioning>
<callGarbageCollector>NONE</callGarbageCollector>
<backup>NONE</backup>
<nonEmptyCachePolicy>NONE</nonEmptyCachePolicy>
<nonEmptyCacheType>REGULAR</nonEmptyCacheType>
<nonEmptyCachePersistency>MEMORY</nonEmptyCachePersistency>
<storagePolicy>DEFAULT</storagePolicy>
<hierarchyUniqueNameStyle>IncludeDimensionName</hierarchyUniqueNameStyle>
<inMemoryDS name="data">
<memoryDataTable tableName="data" rowLimit="-1" id="d9429713-9be8-4c63-9b40-4a20388e7563">
<column name="dimension" tableType="STRING" type="STRING" selected="true" primaryKey="false"/>
<column name="amount" tableType="STRING" type="STRING" selected="true" primaryKey="false"/>
<column name="text" tableType="STRING" type="STRING" selected="true" primaryKey="false"/>
<addRowNumber>false</addRowNumber>
<stringDateConverter></stringDateConverter>
<trimStrings>true</trimStrings>
<columnSeparator>,</columnSeparator>
<commentMarker>#</commentMarker>
<dataAsString>dimension, amount, text
a, 10,some text
b, 20, some more text
c, ,text without an amount</dataAsString>
</memoryDataTable>
</inMemoryDS>
<multiLevelDimension dataTableId="d9429713-9be8-4c63-9b40-4a20388e7563" isTimeDimension="false" isDefaultTimeDimension="false" isIndexingByRange="false" id="86d118f0-71ba-4826-a6ac-343eac96fb05" name="Dimension">
<multiLevelHierarchy hasAllLevel="true" allLevelName="All-Level" allMemberName="All" name="Dimension" isDefault="true">
<level name="Dimension - L" nameUnique="false" nameUniqueInParent="false" keyUnique="false" ignoreNameCollision="false">
<nameCol name="dimension"/>
<orderType>BY_NAME</orderType>
<orderKind>ASC</orderKind>
</level>
</multiLevelHierarchy>
</multiLevelDimension>
<cube id="caa9c520-f953-4c77-9e72-76c8668170f7" name="Cube">
<defaultFacts measureGroupName="Facts" partitioningLevelName="" partitioningType="NONE" newGeneration="true" dataTableId="d9429713-9be8-4c63-9b40-4a20388e7563" aggregateDataSourceFacts="false" unresolvedRowsBehavior="ERROR">
<rowFactAggregationType>ADD_ROW</rowFactAggregationType>
<measure name="Amount" aggregationType="SUM">
<dataColumn name="amount"/>
</measure>
<measure name="Text" aggregationType="MIN">
<dataColumn name="text"/>
</measure>
<links dimensionId="86d118f0-71ba-4826-a6ac-343eac96fb05">
<viewLinks type="LAST_LEVEL">
<toColumns name="dimension"/>
</viewLinks>
</links>
</defaultFacts>
</cube>
</schemaDefinition>
</schemaFactory>
- the mdx
drillthrough
select [Measures].members on 0
, [Dimension].[Dimension].[Dimension - L] on 1
from [cube]
return Name([Dimension])
the result
This is not related to having a measure of type STRING.
You're performing a multi-cell result drillthrough (which is an extension of standard MDX in icCube). In that case, the result is "organized" per result cell meaning each [Measures] being in its own category (you can add another Amount measure and you'll see the same behavior).
Instead you should perform a single cell drillthrough:
drillthrough
select [Dimension].[Dimension].[Dimension -L].[a] on 0
from [cube]
And the result should look like:
You can see the [Measures].[Info] being on the same row (as all the other measures).
Hope that helps.

MDX How to use CASE to check a level value

I'm new to BI and MDX and have a need to do this. I have a dimension that looks like this:
<Dimension name="JobDim">
<Hierarchy name="Job" hasAll="true" primaryKey="jobID">
<Table name="JobDim" schema="dw"/>
<Level name="Job Code" column="jobCode" type="String" uniqueMembers="false"/>
</Hierarchy>
<Hierarchy name="Job Status" hasAll="true" primaryKey="jobID">
<Table name="JobDim" schema="dw"/>
<Level name="Job Status" column="status" type="String" hideMemberIf="IfBlankName"/>
</Hierarchy>
</Dimension>
I have a calculated measure and I need to set the value of this measure depending on the 'job status', so if the job is 'complete', set the measure to 100, otherwise set its value to 200 (the value to be used is more complex but for this example purpose, this is good enough). I'm using something like this:
<CalculatedMember name="Earned Revenue" dimension="Measures" formatString="$#,###.00;($#,###.00)" aggregator="sum">
<Formula>case [JobDim.Job Status].CurrentMember
when [JobDim.Job Status].[Complete] then 100
else 200
end
</Formula>
</CalculatedMember>
I've tried different variations of the code above, but none seem to work (some even cause a crash when I try to run the report). Anyone has done something like this in the past that can provide me an answer?
You need to evaluate that tuple against some measure. Remember that in MDX evaluations are done against the level/aggregate results, not on a row by row basis.
From your description it looks like Job Status should be a property of the level Job Code, and not a level.
Try the following on your schema:
<Dimension name="JobDim">
<Hierarchy name="Job" hasAll="true" primaryKey="jobID">
<Table name="JobDim" schema="dw"/>
<Level name="Job Code" column="jobCode" type="String" uniqueMembers="false">
<Property name="Job Status" column="status" type="String"/>
</Level>
</Hierarchy>
</Dimension>
and on your calculated measure
<CalculatedMember name="Earned Revenue" dimension="Measures" formatString="$#,###.00;($#,###.00)" aggregator="sum">
<Formula>case [JobDim.Job Status].CurrentMember.Properties("Job Status")
when "Complete" then 100
else 200
end
</Formula>
</CalculatedMember>
Better to use IIF than CASE if possible as it is generally quicker. Assuming [JobDim.Job Status].[Complete] is a member in your cube then the IS operator should be ok to use:
IIF(
[JobDim.Job Status].CurrentMember
IS [JobDim.Job Status].[Complete]
,100
,200
)

Read multi level XML in and write back to single data base table

I'm a nube with asp.net. This is what I'm trying to achieve. I want to write the following XML data into a single table in a sql server database.
- <RaceDay RaceDayDate="2012-05-16T00:00:00" Year="2012" Month="5" Day="16" DayOfTheWeek="Wednesday" MonthLong="May" IsCurrentDay="1" IsPresaleMeeting="0" ServerTime="2012-05-16T16:47:30.033">
- <Race RaceNo="7" RaceTime="2012-05-16T16:36:00" CloseTime="2012-05-16T16:40:08.107" RaceName="F&M BM 70 HANDICAP" Distance="1200" SubFav="1" RaceDisplayStatus="PAYING" WeatherChanged="N" WeatherCond="1" WeatherDesc="Fine" TrackChanged="N" TrackCond="1" TrackDesc="Good" TrackRating="3" TrackRatingChanged="N">
- <TipsterTip TipsterId="0" Tips="1">
<Tipster TipsterName="LATE MAIL" />
</TipsterTip>
- <TipsterTip TipsterId="1" Tips="8-5-3-7">
<Tipster TipsterName="RADIO TAB" />
</TipsterTip>
- <TipsterTip TipsterId="2" Tips="1-10-9-2">
<Tipster TipsterName="KEVIN CASEY" />
</TipsterTip>
- <Pool PoolType="EX" Available="Y" Abandoned="N" PoolDisplayStatus="PAYING" PoolTotal="3734.00" JPotInGross="0.00" JPotOutGross="0.00" LastCalcTime="2012-05-16T16:36:57" CalcTime="2012-05-16T16:41:31" StatDiv="0">
- <Dividend DivId="62406790" DivAmount="80.8000">
<DivResult LegNo="1" RunnerNo="7" />
<DivResult LegNo="2" RunnerNo="5" />
</Dividend>
</Pool>
- <Pool PoolType="F4" Available="Y" Abandoned="N" PoolDisplayStatus="PAYING" PoolTotal="3492.00" JPotInGross="0.00" JPotOutGross="1397.16" LastCalcTime="2012-05-16T16:36:57" CalcTime="2012-05-16T16:41:31" StatDiv="0">
- <Dividend DivId="62406797" DivAmount="10828.0000">
<DivResult LegNo="1" RunnerNo="7" />
<DivResult LegNo="2" RunnerNo="5" />
<DivResult LegNo="3" RunnerNo="13" />
<DivResult LegNo="4" RunnerNo="1" />
</Dividend>
</Pool>
- <Pool PoolType="QN" Available="Y" Abandoned="N" PoolDisplayStatus="PAYING" PoolTotal="7029.00" JPotInGross="0.00" JPotOutGross="0.00" LastCalcTime="2012-05-16T16:36:57" CalcTime="2012-05-16T16:41:31" StatDiv="0">
- <Dividend DivId="62406785" DivAmount="68.5000">
<DivResult LegNo="1" RunnerNo="5" />
<DivResult LegNo="2" RunnerNo="7" />
</Dividend>
</Pool>
</Race>
</Meeting>
</RaceDay>
Can someone please show me how to read in my xml file and flatten out the data and insert it into a suitable table in the sql database.
Thanks in advance.
Search in web, there are lots of article described about your requirement. Try this one:
Best way to load XML files to SQL Server using C#
And
Importing Large Xml Files to SQL Server Using SqlBulkCopy
First you have to parse the XML and store that into custom C# object or you can directly pass the XML to your stored procedure and do the codding there for saving it into DB.
Passing the xml to stored procedure and manipulating it there is bit difficult so what I suggest is to parse it in C# and then get a custom object. Once you get it you can do whatever you want to.
Here is my article that explains exactly what you need.
Read XML file in ASP.NET(C#)
Below is the sample code that parse a XML file and generate a custom C# object from it.
public CatSubCatList GenerateCategoryListFromProductFeedXML()
{
string path = System.Web.HttpContext.Current.Server.MapPath(_xmlFilePath);
XDocument xDoc = XDocument.Load(path);
XElement xElement = XElement.Parse(xDoc.ToString());
List<Category> lstCategory = xElement.Elements("Product").Select(d => new Category
{
Code = Convert.ToString(d.Element("CategoryCode").Value),
CategoryPath = d.Element("CategoryPath").Value,
Name = GetCateOrSubCategory(d.Element("CategoryPath").Value, 0), // Category
SubCategoryName = GetCateOrSubCategory(d.Element("CategoryPath").Value, 1) // Sub Category
}).GroupBy(x => new { x.Code, x.SubCategoryName }).Select(x => x.First()).ToList();
CatSubCatList catSubCatList = GetFinalCategoryListFromXML(lstCategory);
return catSubCatList;
}

Resources