Converting string to element in Marklogic Xquery - xquery

I have the following XQuery script that basically adds properties to an existing document in MarkLogic:
xquery version "1.0-ml";
declare namespace xhtml = "http://www.w3.org/1999/xhtml";
declare namespace error="http://marklogic.com/xdmp/error";
declare namespace cdata = "http://www.w3.org/1999/cdata";
declare variable $uri as xs:string external;
declare variable $contentproperties as xs:string external;
xdmp:document-add-properties($uri, ( $contentproperties ) );
The external C# program calls this query and passes in the following as string for the $contentproperties:
<Title>My Title</Title>,<Date>1629076218</Date>,<SubjectArea>My subject</SubjectArea>,<ContentType>My content type</ContentType>,<Summary>My summary</Summary>
However, an error returns mentioning that:
XDMP-ARGTYPE: (err:XPTY0004) xdmp:document-add-properties("", "My Title,1629076218,My ...") -- arg2 is not of type element()*"
How should I convert xs:string to element()* type?
Reference to the document-add-properties method: https://docs.marklogic.com/xdmp:document-add-properties

You can tokenize() that string of comma separated values, then use xdmp:unquote() to parse the XML string into an XML document, and then XPath to the element. Assign that sequence of elements to another variable, and use that variable to set your properties:
xquery version "1.0-ml";
declare namespace xhtml = "http://www.w3.org/1999/xhtml";
declare namespace error="http://marklogic.com/xdmp/error";
declare namespace cdata = "http://www.w3.org/1999/cdata";
declare variable $uri as xs:string external := "test";
declare variable $contentproperties as xs:string external := "<Title>My Title</Title>,<Date>1629076218</Date>,<SubjectArea>My subject</SubjectArea>,<ContentType>My content type</ContentType>,<Summary>My summary</Summary>";
declare variable $contentproperties-element as element()* := tokenize($contentproperties, ",") ! xdmp:unquote(.)/*;
xdmp:document-add-properties($uri, ( $contentproperties-element ) );

Related

Define variable to to be type of record attribute pl/sql

Suppose I have the following code snippet in PL/SQL:
type my_record is record(
CUST_ID number(7);
CUST_NAME varchar2(200);
);
Now i want to declare a variable which takes the same type as cust_name:
my_title my_record.cust_name%type;
This is what I tried and I get error 'PLS-00206:%TYPE must be applied to variable, column, field or attribute...I believe I'm doing what Oracle's documentation is showing...http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/type_attribute.htm
I'd prefer not to hard code the variable type, in the situation the CUST_NAME type is ever changed.
see the very first line of the article, you posted.
it reads as "The %TYPE attribute lets you declare a constant, variable, field, or parameter to be of the same data type a previously declared variable, field, record, nested table, or database column."
Here you tried applying %TYPE on a record type and not on record.
Declare
Type my_record is record(
CUST_ID number(7);
CUST_NAME varchar2(200);
);
my_var my_record ;
my_new_var my_var.CUST_NAME%type;
begin
null;
end;
You need to do it the other way around. If you declare a variable first (using %type if you want), the record definition can reference that as somevariable%type. Or else declare a subtype first and reference that in both places.
Create variable of record type. And apply %type to this variable;
DECLARE
type my_record is record(
CUST_ID number(7),
CUST_NAME varchar2(200)
);
myRec my_record;
my_title myRec.cust_name%type;
BEGIN
NULL;
END;

Using CLOB instead of VARCHAR2

We want to create an XML. The current code does it by appending one XML tag at a time to a VARCHAR2 variable.
xmlString VARCHAR2(32767);
....
....
xmlString := xmlString || '<' || elementName || '>' || elementValue || '</' || elementName || '>';
However due to size limitation of 32767 characters on VARCHAR2, we get the following error for a very long XML.
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
The solution we have is to declare a CLOB and write a procedure to keep flushing the VARCHAR2 variable to the CLOB.
v_result clob;
.....
.....
IF xmlString IS NOT NULL THEN
dbms_lob.writeappend( v_result, LENGTH(xmlString), xmlString);
xmlString := NULL;
END IF;
However this would require replacing lots of exiting code lines with calls to the new function. Is there a better way to do this?
Anything similar to Operator Overloading in PLSQL? Can I change the data type of xmlString variable to CLOB and make the || operator to do the work of dbms_lob.writeappend?
Yes, if you change the data type of xmlString to clob, the string concatenation operator will continue to work.
However, building XML this way would be a very poor architecture. That's the sort of architecture that has a high probability of generating invalid XML when, for example, one of the strings happens to have a character that needs to be escaped (or for any of a number of different reasons). Oracle provides a whole host of functions to generate XML (XMLElement, XMLForest, SYS_XMLGen, DBMS_XMLQuery, etc. depending on your use case). It would be far better architecturally to use those built-in functions.

pl/sql function showing syntax error

I am new in pl/sql. i have write a pl/sql function using sql developer with proper
package name & body.
I function is showing this error:
image given below:
Here is the pl/sql code:
create or replace PACKAGE PAYROLL AS
FUNCTION save_payroll_transaction(transaction_data NVARCHAR2 ) RETURN nclob;
END PAYROLL;
Body:
create or replace PACKAGE BODY PAYROLL IS
FUNCTION save_payroll_transaction(transaction_data NVARCHAR2 ) RETURN nclob IS ret nclob;
xmlData XMLType;
BEGIN
xmlData:=XMLType(transaction_data);
INSERT INTO PAYROLLFILE SELECT x.* FROM XMLTABLE('/transaction'
PASSING xmlData
COLUMNS "salary_year" NUMBER(4,0) PATH "SALYR",
"salary_month" NUMBER(2,0) PATH "SALMT",
"employee_id" NUMBER PATH "EMPID",
"department_code" NUMBER PATH "DPTID",
"salary_head" VARCHAR2(2) PATH "SALHD",
"description" VARCHAR2(50) PATH "DESCR",
"amount" FLOAT(126) PATH "ALAMT",
"operator_id" NUMBER PATH "OPID",
"transaction_date" DATE PATH "TRADT") x;
ret:=to_char(sql%rowcount);
COMMIT;
RETURN '<result><status affectedRow='||ret||'>success</status></result>';
EXCEPTION
WHEN OTHERS THEN
RETURN '<result><status>Error</status></result>';
END save_payroll_transaction;
END PAYROLL;
please help.Thanks
XML path is a string, not an identifier, so you need to enclose it in single quotes:
"salary_year" NUMBER(4,0) PATH 'SALYR' -- not "SALYR"

array must be declare error in pl sql

I want to return a array in a function as my function looks like below,
CREATE OR REPLACE FUNCTION TEST
RETURN t_array
IS
strings t_array;
BEGIN
--do something
RETURN strings;
END:
But it gives a error t_array must be declare. I want to know where to declare it and how can i declare it?
When you are using a custom type, you have to declare that type first. For example:
CREATE OR REPLACE TYPE string_array IS TABLE OF varchar2(50);
Which creates a new type named string_array that is a table of varchars.
For more information check the official oracle dokumentation here

HTML Encoding in T-SQL?

Is there any function to encode HTML strings in T-SQL? I have a legacy database which contains dodgey characters such as '<', '>' etc. I can write a function to replace the characters but is there a better way?
I have an ASP.Net application and when it returns a string it contains characters which cause an error. The ASP.Net application is reading the data from a database table. It does not write to the table itself.
We have a legacy system that uses a trigger and dbmail to send HTML encoded email when a table is entered, so we require encoding within the email generation. I noticed that Leo's version has a slight bug that encodes the & in < and > I use this version:
CREATE FUNCTION HtmlEncode
(
#UnEncoded as varchar(500)
)
RETURNS varchar(500)
AS
BEGIN
DECLARE #Encoded as varchar(500)
--order is important here. Replace the amp first, then the lt and gt.
--otherwise the &lt will become &lt;
SELECT #Encoded =
Replace(
Replace(
Replace(#UnEncoded,'&','&'),
'<', '<'),
'>', '>')
RETURN #Encoded
END
GO
It's a bit late, but anyway, here the proper ways:
HTML-Encode (HTML encoding = XML encoding):
DECLARE #s NVARCHAR(100)
SET #s = '<html>unsafe & safe Utf8CharsDon''tGetEncoded ÄöÜ - "Conex"<html>'
SELECT (SELECT #s FOR XML PATH(''))
HTML-encode in a query:
SELECT
FIELD_NAME
,(SELECT FIELD_NAME AS [text()] FOR XML PATH('')) AS FIELD_NAME_HtmlENcoded
FROM TABLE_NAME
HTML-Decode:
SELECT CAST('<root>' + '<root>Test&123' + '</root>' AS XML).value(N'(root)[1]', N'varchar(max)');
If you want to do it properly, you can use a CLR-stored procedure.
However, it gets a bit complicated, because you can't use the System.Web-Assembly in CLR-stored-procedures (so you can't do System.Web.HttpUtility.HtmlDecode(htmlEncodedStr);). So you have to write your own HttpUtility class, which I wouldn't recommend, especially for decoding.
Fortunately, you can rip System.Web.HttpUtility out of the mono sourcecode (.NET for Linux). Then you can use HttpUtility without referencing system.web.
Then you write this CLR-Stored-Procedure:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
//using Microsoft.SqlServer.Types;
namespace ClrFunctionsLibrary
{
public class Test
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString HtmlEncode(SqlString sqlstrTextThatNeedsEncoding)
{
string strHtmlEncoded = System.Web.HttpUtility.HtmlEncode(sqlstrTextThatNeedsEncoding.Value);
SqlString sqlstrReturnValue = new SqlString(strHtmlEncoded);
return sqlstrReturnValue;
}
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString HtmlDecode(SqlString sqlstrHtmlEncodedText)
{
string strHtmlDecoded = System.Web.HttpUtility.HtmlDecode(sqlstrHtmlEncodedText.Value);
SqlString sqlstrReturnValue = new SqlString(strHtmlDecoded);
return sqlstrReturnValue;
}
// ClrFunctionsLibrary.Test.GetPassword
//[Microsoft.SqlServer.Server.SqlFunction]
//public static SqlString GetPassword(SqlString sqlstrEncryptedPassword)
//{
// string strDecryptedPassword = libPortalSecurity.AperturePortal.DecryptPassword(sqlstrEncryptedPassword.Value);
// SqlString sqlstrReturnValue = new SqlString(sqlstrEncryptedPassword.Value + "hello");
// return sqlstrReturnValue;
//}
public const double SALES_TAX = .086;
// http://msdn.microsoft.com/en-us/library/w2kae45k(v=vs.80).aspx
[SqlFunction()]
public static SqlDouble addTax(SqlDouble originalAmount)
{
SqlDouble taxAmount = originalAmount * SALES_TAX;
return originalAmount + taxAmount;
}
} // End Class Test
} // End Namespace ClrFunctionsLibrary
And register it:
GO
/*
--http://stackoverflow.com/questions/72281/error-running-clr-stored-proc
-- For unsafe permission
EXEC sp_changedbowner 'sa'
ALTER DATABASE YOUR_DB_NAME SET TRUSTWORTHY ON
GO
*/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[HtmlEncode]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[HtmlEncode]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[HtmlDecode]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[HtmlDecode]
GO
IF EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name = N'ClrFunctionsLibrary' and is_user_defined = 1)
DROP ASSEMBLY [ClrFunctionsLibrary]
GO
--http://msdn.microsoft.com/en-us/library/ms345101.aspx
CREATE ASSEMBLY [ClrFunctionsLibrary]
AUTHORIZATION [dbo]
FROM 'D:\username\documents\visual studio 2010\Projects\ClrFunctionsLibrary\ClrFunctionsLibrary\bin\Debug\ClrFunctionsLibrary.dll'
WITH PERMISSION_SET = UNSAFE --EXTERNAL_ACCESS --SAFE
;
GO
CREATE FUNCTION [dbo].[HtmlDecode](#value [nvarchar](max))
RETURNS [nvarchar](max) WITH EXECUTE AS CALLER
AS
-- [AssemblyName].[Namespace.Class].[FunctionName]
EXTERNAL NAME [ClrFunctionsLibrary].[ClrFunctionsLibrary.Test].[HtmlDecode]
GO
CREATE FUNCTION [dbo].[HtmlEncode](#value [nvarchar](max))
RETURNS [nvarchar](max) WITH EXECUTE AS CALLER
AS
-- [AssemblyName].[Namespace.Class].[FunctionName]
EXTERNAL NAME [ClrFunctionsLibrary].[ClrFunctionsLibrary.Test].[HtmlEncode]
GO
/*
EXEC sp_CONFIGURE 'show advanced options' , '1';
GO
RECONFIGURE;
GO
EXEC sp_CONFIGURE 'clr enabled' , '1'
GO
RECONFIGURE;
GO
EXEC sp_CONFIGURE 'show advanced options' , '0';
GO
RECONFIGURE;
*/
Afterwards, you can use it like normal functions:
SELECT
dbo.HtmlEncode('helloäÖühello123') AS Encoded
,dbo.HtmlDecode('helloäÖühello123') AS Decoded
Anybody who just copy-pastes, please note that for efficiency reasons, you would use
public const double SALES_TAX = 1.086;
// http://msdn.microsoft.com/en-us/library/w2kae45k(v=vs.80).aspx
[SqlFunction()]
public static SqlDouble addTax(SqlDouble originalAmount)
{
return originalAmount * SALES_TAX;
}
if you'd use this function in production.
See here for the edited mono classes:
http://pastebin.com/pXi57iZ3
http://pastebin.com/2bfGKBte
You need to define NET_2_0 in the build options
You shouldn't fix the string in SQL. A better way is to use a function in ASP.net called HtmlEncode, this will cook the special characters that cause the issues you're seeing see the example below. I hope this helps.
string htmlEncodedStr = System.Web.HttpUtility.HtmlEncode(yourRawStringVariableHere);
string decodedRawStr = System.Web.HttpUtility.HtmlDecode(htmlEncodedStr);
Edit:
Since you're data binding this from a datatable. Use an inline expression to call HTMLEncode in the markup of the GridView or whatever control your using and this will still satisfy your data binding requirement. See example below. Alternativly you can loop every record in the data table object and update each cell with the html encoded string prior to data binding.
<%# System.Web.HttpUtility.HtmlEncode(Eval("YourColumnNameHere")) %>
I don't think data in a database should know or care about the user interface. Display issues should be handled by the presentation layer. I wouldn't want to see any HTML mingled into the database.
You can simply use 'XML PATH in your query'. For example;
DECLARE #encodedString VARCHAR(MAX)
SET #encodedString = 'give your html string you want to encode'
SELECT #encodedString
SELECT (SELECT #encodedString FOR XML PATH(''))
Now as your wish you can you this in your own sql function. Hope this will help.
If you're displaying a string on the web, you can encode it with Server.HTMLEncode().
If you're storing a string in the database, make sure the database field is "nchar", instead of "char". That will allow it to store unicode strings.
If you can't control the database, you can "flatten" the string to ASCII with Encoding.ASCII.GetString.
I haven't tried this solution myself but what I would try is utilise the sql server / .NET CLR integration and actually call the C# HTMLEncode function from the T-SQL.
This may be inefficient but I suspect it would give you the most accurate result.
My starting point for working out how to do this would be http://msdn.microsoft.com/en-us/library/ms254498%28VS.80%29.aspx
I've been trying to do this today in T-SQL, mostly for fun at this point since my requirements changed, but i figured one way out. You can use a table of unicode characters, built from the NCHAR() function or just import it, iterating from 0 to 65535 (or less if you just need the first 512 or something). Then rebuild the string. There are probably better ways to rebuild the string, but this works in a pinch.
---store unicode chars into a table so you can replace those characters withthe decimal value
`
CREATE TABLE #UnicodeCharacters(
DecimalValue INT,
UnicodeCharacter NCHAR
)
;
--loop from 0 to highest unicode value you want and dump to the table you created
DECLARE #x INT = 0;
WHILE #x <= 65535
BEGIN
BEGIN
INSERT INTO #UnicodeCharacters(DecimalValue, UnicodeCharacter)
SELECT #x,NCHAR(#x)
END
;
SET #x = #x + 1
;
END
;
--index for fast retrieval
CREATE CLUSTERED INDEX CX_UnicodeCharacter_DecimalValue ON #UnicodeCharacters(UnicodeCharacter, DecimalValue);
--this is the string that you want to html-encode...
DECLARE #String NVARCHAR(100) = N'人This is a test - Ñ';
--other vars
DECLARE #NewString NVARCHAR(100) = '';
DECLARE #Word TABLE(Character NCHAR(1));
DECLARE #Pos INT = 1;
--run through the string and check each character to see if it is outside the regex expression
WHILE #Pos <= LEN(#String)
BEGIN
DECLARE #Letter NCHAR(1) = SUBSTRING(#String,#Pos,1);
PRINT #Letter;
--rebuild the string replacing each unicode character outside the regex with &#[unicode value];
SELECT #NewString = #NewString +
CASE
WHEN #Letter LIKE N'%[0-9abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-!##$%^&*()_+-= ]%' THEN #Letter
ELSE '&#' + CAST(uc.DecimalValue AS VARCHAR(10)) + ';'
END
FROM #UnicodeCharacters uc
WHERE #Letter = uc.UnicodeCharacter COLLATE JAPANESE_UNICODE_BIN
SET #Pos += 1
END
--end result
SELECT #NewString
;
`
I know typically you would use [0-9A-Za-z], but for some reason, it considered accented characters within the scope of that expression when I did that. So I explicitly used every character that i didn't want to convert to Unicode in the expression.
Last note, I had to use a different collation to do matches on Unicode characters, because the default LATIN collation (CI or otherwise) seemed to incorrectly match on accented characters, much like the regex in the LIKE.
assign it to Text Property of label, it will be auto encoded by .NET
OK here is what I did. I created a simple function to handle it. Its far from complete but at least handles the standard <>& characters. I'll just add to it as I go along.
CREATE FUNCTION HtmlEncode
(
#UnEncoded as varchar(500)
)
RETURNS varchar(500)
AS
BEGIN
DECLARE #Encoded as varchar(500)
SELECT #Encoded = Replace(#UnEncoded,'<','<')
SELECT #Encoded = Replace(#Encoded,'>','>')
SELECT #Encoded = Replace(#Encoded,'&','&')
RETURN #Encoded
END
I can then use:
Select Ref,dbo.HtmlEncode(RecID) from Customers
This gives me a HTML safe Record ID. There is probably a built in function but I can't find it.

Resources