I'm using Apache FOP with the IKVM from my c# code. I generate the pdf by using the xslt stylesheet to get the result as xsl fo. I have one problem, that is usingthe custom functions.
My stylesheet declaration:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:cal="xalan://m.test"
extension-element-prefixes="cal"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2001/XMLSchema-instance http://www.xmlblueprint.com/documents/fop.xsd">
The custom function:
namespace m
{
public class test
{
public static string zzz(ExpressionContext x, object d)
{
return "test";
}
}
}
And calling this from the xslt:
<xsl:value-of select="cal:zzz(1)"/>
Code to compile it:
FopFactory fopFactory = FopFactory.newInstance();
fopFactory.ignoreNamespace("http://www.w3.org/2001/XMLSchema-instance");
fopFactory.setUserConfig(new File("fop.xconf"));
OutputStream o = new DotNetOutputMemoryStream();
try
{
Fop fop = fopFactory.newFop("application/pdf", o);
TransformerFactory factory = TransformerFactory.newInstance();
Source xsltSrc = new StreamSource(new File("data.xsl"));
Transformer transformer = factory.newTransformer(xsltSrc);
var bytes = System.IO.File.ReadAllBytes("data.xml"); //"HR_CV.fo");
var stream = new DotNetInputMemoryStream(new System.IO.MemoryStream(bytes));
Source src = new StreamSource(stream);
Result res = new SAXResult(fop.getDefaultHandler());
transformer.transform(src, res);
}
finally
{
o.close();
}
Exception I got is:
java.lang.NoSychMethodExtension: For extension function, could not find method org.apache.xml.utils.NodeVector.zzz([ExpressionContext,])
What I'm doing wrong?
You're calling the zzz function with a single argument (1). But your function expects two arguments. If you provide both arguments, chances are it will work just fine.
Related
According to my task I have to invoke SOAP service. So, I have generated java classes from wsdl using xjc. But I have a problem invoking SOAP service. My application generates this request:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/><soap:Body>
<typ:SendMessage xmlns:ns4="http://test.user.kz/UserInfo" xmlns:q1="http://test.user.kz/CustomerInfo" xmlns:typ="http://test.user.kz/MyChannel/v1/Types">
<request>
<requestInfo>
<messageId>26e96b11-8f82-421e-829a</messageId>
</requestInfo>
<requestData>
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="q1:PaymentPackageRequestType">
<q1:methodName>testMethod</q1:methodName>
</data>
</requestData>
</request>
</typ:SendMessage></soap:Body></soap:Envelope>
But I need in my SOAP request I need to specify namespace in data tag, lik this:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/><soap:Body>
<typ:SendMessage xmlns:ns4="http://test.user.kz/UserInfo" xmlns:q1="http://test.user.kz/CustomerInfo" xmlns:typ="http://test.user.kz/MyChannel/v1/Types">
<request>
<requestInfo>
<messageId>26e96b11-8f82-421e-829a</messageId>
</requestInfo>
<requestData>
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="q1:PaymentPackageRequestType" **xmlns:q1="http://payments.bee.kz/PaymentPackage"**>
<q1:methodName>testMethod</q1:methodName>
</data>
</requestData>
</request>
</typ:SendMessage></soap:Body></soap:Envelope>
Otherwise target SOAP service gives me error:
XML namespace prefix 'q1' is not defined.
How it possible to specify namespace in data tag?
This is my current package-info:
#javax.xml.bind.annotation.XmlSchema(
xmlns = {
#javax.xml.bind.annotation.XmlNs(prefix = "typ",
namespaceURI = "http://test.user.kz/MyChannel/v1/Types"),
#javax.xml.bind.annotation.XmlNs(prefix = "q1",
namespaceURI = "http://test.user.kz/CustomerInfo")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.UNQUALIFIED,
attributeFormDefault = javax.xml.bind.annotation.XmlNsForm.UNSET
)
package kz.uni.gen;
So I couldn't add namespace xmlns:q1="http://test.user.kz/CustomerInfo" to data tag in SOAP request. How can I add this namespace declaration or move namespace declaration from SendMessage tag?
so using JAXB it is not possible. Therefore I am manually added namespace in required element. This is full snippet:
Document document = null;
try {
document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Marshaller marshaller = JAXBContext.newInstance(SendMessage.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty("com.sun.xml.bind.characterEscapeHandler", new CharacterEscapeHandler() {
#Override
public void escape(char[] buf, int start, int len, boolean b, Writer out) throws IOException {
out.write(buf, start, len);
}
});
QName name = new QName(NAMESPACE_URI, SendMessage.class.getSimpleName());
JAXBElement<SendMessage> root = new JAXBElement<SendMessage>(name, SendMessage.class, from);
StringWriter writer1 = new StringWriter();
marshaller.marshal(root, writer1);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Element node = dbf
.newDocumentBuilder()
.parse(new ByteArrayInputStream(writer1.toString().getBytes(StandardCharsets.ISO_8859_1)))
.getDocumentElement();
Attr attr1 = document.createAttribute("xmlns:q1");
attr1.setValue("http://test.user.kz/CustomerInfo");
node.getElementsByTagName("data").item(0).getAttributes().setNamedItem(node.getOwnerDocument().importNode(attr1, true));
return node;
} catch (Exception e) {
throw new Exception("Unable to transform POJO to XML SOAP message ", e);
}
I can successfully use Xerces XPath feature to query for information from an XML with the following XML and C++ code.
XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<ApplicationSettings>
hello universe
</ApplicationSettings>
</root>
C++
int main()
{
XMLPlatformUtils::Initialize();
// create the DOM parser
XercesDOMParser *parser = new XercesDOMParser;
parser->setValidationScheme(XercesDOMParser::Val_Never);
parser->parse("fake_cmf.xml");
// get the DOM representation
DOMDocument *doc = parser->getDocument();
// get the root element
DOMElement* root = doc->getDocumentElement();
// evaluate the xpath
DOMXPathResult* result=doc->evaluate(
XMLString::transcode("/root/ApplicationSettings"), // <-- HERE IS THE XPATH
root,
NULL,
DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, //DOMXPathResult::ANY_UNORDERED_NODE_TYPE, //DOMXPathResult::STRING_TYPE,
NULL);
// look into the xpart evaluate result
result->snapshotItem(0);
std::cout<<TranscodeToStr(result->getNodeValue()->getFirstChild()->getNodeValue(),"ascii").str()<<std::endl;;
XMLPlatformUtils::Terminate();
return 0;
}
The problem is that sometimes my XML will only have certain fields. But if I remove the ApplicationSettings entry from the XML it will seg fault. How can I properly handle these optional fields? I know that trying to correct from seg faults is risky business.
The seg fault is occurring in this line
std::cout<<TranscodeToStr(result->getNodeValue()->getFirstChild()->getNodeValue(),"ascii").str()<<std::endl;
specifically in get getFirstChild() call because the result of getNodeValue() is NULL.
This is my quick and dirty solution. It's not really ideal but it works. I would prefer a more sophisticated evaluation and response.
if (result->getNodeValue() == NULL)
{
cout << "There is no result for the provided XPath " << endl;
}
else
{
cout<<TranscodeToStr(result->getNodeValue()->getFirstChild()->getNodeValue(),"ascii").str()<<endl;
}
Doing something like this:
using (XmlWriter myMamlHelpWriter = XmlWriter.Create(myFileStream, XmlHelpExToMamlXslTransform.OutputSettings))
{
XmlHelpExToMamlXslTransform.Transform(myMsHelpExTopicFilePath, null, myMamlHelpWriter);
}
where
private static XslCompiledTransform XmlHelpExToMamlXslTransform
{
get
{
if (fMsHelpExToMamlXslTransform == null)
{
// Create the XslCompiledTransform and load the stylesheet.
fMsHelpExToMamlXslTransform = new XslCompiledTransform();
using (Stream myStream = typeof(XmlHelpBuilder).Assembly.GetManifestResourceStream(
typeof(XmlHelpBuilder),
MamlXmlTopicConsts.cMsHelpExToMamlTransformationResourceName))
{
XmlTextReader myReader = new XmlTextReader(myStream);
fMsHelpExToMamlXslTransform.Load(myReader, null, null);
}
}
return fMsHelpExToMamlXslTransform;
}
}
And every time the string """ is replaced with real quotes in the result file.
Cannot understand why this happens...
The reason is that in the XSLT's internal representation, " is exactly the same characer as ". They both represent the ascii code point 0x34. It would seem that when the XslCompiledTransform produces its output, it uses " where it's legal to do so. I would imagine that it would still output " inside an attribute value.
Is it a problem for you that " is produced as " in the output?
I just ran the following XSLT in Visual Studio using an arbitrary input file:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/*">
<xml>
<xsl:variable name="chars">"'<>&</xsl:variable>
<node a='{$chars}' b="{$chars}">
<xsl:value-of select="$chars"/>
</node>
</xml>
</xsl:template>
</xsl:stylesheet>
The output was:
<xml>
<node a=""'<>&" b=""'<>&">"'<>&</node>
</xml>
As you can see, even though all five characters were represented as entities originally, the apostrophies are produced as ' everywhere, and quotation marks are produced as " in text nodes. Furthermore, the a attribute which had ' delimiters uses " delimiters in the output. As I said, as far as the XSLT cares, a quotation mark is just a quotation mark, and an attribute is just an attribute. How those are produced in the output is up to the XSLT processor.
Edit: The root cause of this behavior appears to be the behavior of the XmlWriter class. It looks like the general suggestion for those who want more customized escaping is to extend the XmlTextWriter class. This page has an implementation that looks fairly promising:
public class KeepEntityXmlTextWriter : XmlTextWriter
{
private static readonly string[] ENTITY_SUBS = new string[] { "'", """ };
private static readonly char[] REPLACE_CHARS = new char[] { '\'', '"' };
public KeepEntityXmlTextWriter(string filename) : base(filename, null) { ; }
private void WriteStringWithReplace(string text)
{
string[] textSegments = text.Split(KeepEntityXmlTextWriter.REPLACE_CHARS);
if (textSegments.Length > 1)
{
for (int pos = -1, i = 0; i < textSegments.Length; ++i)
{
base.WriteString(textSegments[i]);
pos += textSegments[i].Length + 1;
// Assertion: Replace the following if-else when the number of
// replacement characters and substitute entities has grown
// greater than 2.
Debug.Assert(2 == KeepEntityXmlTextWriter.REPLACE_CHARS.Length);
if (pos != text.Length)
{
if (text[pos] == KeepEntityXmlTextWriter.REPLACE_CHARS[0])
base.WriteRaw(KeepEntityXmlTextWriter.ENTITY_SUBS[0]);
else
base.WriteRaw(KeepEntityXmlTextWriter.ENTITY_SUBS[1]);
}
}
}
else base.WriteString(text);
}
public override void WriteString( string text)
{
this.WriteStringWithReplace(text);
}
}
On the other hand, the MSDN documentation recommends using XmlWriter.Create() rather than instantiating XmlTextWriters directly.
In the .NET Framework 2.0 release, the recommended practice is to create XmlWriter instances using the XmlWriter.Create method and the XmlWriterSettings class. This allows you to take full advantage of all the new features introduced in this release. For more information, see Creating XML Writers.
One way around that would be to use the same logic as above, but put it in a class that wraps an XmlWriter. This page has a ready-made implementation of an XmlWrappingWriter, that you can modify as needed.
To use the above code with the XmlWrappingWriter, you would subclass the wrapping writer, like this:
public class KeepEntityWrapper : XmlWrappingWriter
{
public KeepEntityWrapper(XmlWriter baseWriter)
: base(baseWriter)
{
}
private static readonly string[] ENTITY_SUBS = new string[] { "'", """ };
private static readonly char[] REPLACE_CHARS = new char[] { '\'', '"' };
private void WriteStringWithReplace(string text)
{
string[] textSegments = text.Split(REPLACE_CHARS);
if (textSegments.Length > 1)
{
for (int pos = -1, i = 0; i < textSegments.Length; ++i)
{
base.WriteString(textSegments[i]);
pos += textSegments[i].Length + 1;
// Assertion: Replace the following if-else when the number of
// replacement characters and substitute entities has grown
// greater than 2.
Debug.Assert(2 == REPLACE_CHARS.Length);
if (pos != text.Length)
{
if (text[pos] == REPLACE_CHARS[0])
base.WriteRaw(ENTITY_SUBS[0]);
else
base.WriteRaw(ENTITY_SUBS[1]);
}
}
}
else base.WriteString(text);
}
public override void WriteString(string text)
{
this.WriteStringWithReplace(text);
}
}
Note this essentially the same code as the KeepEntityXmlTextWriter, but using XmlWrappingWriter as the base class and with a different constructor.
I don't recognize the Guard that the XmlWrappingWriter code is using in two places, but given that you'll be consuming the code yourself, it should be pretty safe to delete the lines like this. They just ensure that a null value isn't passed to the constructor or the (in the above case inaccessible) BaseWriter property:
Guard.ArgumentNotNull(baseWriter, "baseWriter");
To create an instance of the XmlWrappingWriter, you would create an XmlWriter however you need to, and then use:
KeepEntityWrapper wrap = new KeepEntityWrapper(writer);
And then you'd use this wrap variable as the XmlWriter you pass to your XSL transform.
The XSLT processor doesn't know whether a character was represented by a character entity or not. This is because the XML parser substitutes any character entity with its code-value.
Therefore, the XSLT processor would see exactly the same character, regardless whether it was represented as " or as " or as " or as ".
What you want can be achieved in XSLT 2.0 by using the so called "character maps".
Here is the trick you wanted:
replace all & with &
perform XSLT
replace all & with &
I have a webservice created with jax-ws and netbeans 7's wizard (this is my first time) .
to use java.util.Date instead of XmlGregorianCalendar, I have modified the client's webservice with this xml :
<?xml version="1.0" encoding="UTF-8"?>
<jaxws:bindings node="wsdl:definitions/wsdl:types/xsd:schema"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jaxb:globalBindings>
<jaxb:serializable/>
<jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime"/>
</jaxb:globalBindings>
</jaxws:bindings>
Date is now used instead of XmlGregorianCalendar and an Adapter1 is generated :
public class Adapter1
extends XmlAdapter<String, Date>
{
public Date unmarshal(String value) {
return new Date(value);
}
public String marshal(Date value) {
if (value == null) {
return null;
}
return value.toString();
}
}
When i add a system.out.println in the adapter i see that the Date is received/sent to the server but if i use ws's methods i get always null on Date field/parameters .
Thanks .
The XmlAdapter that is generated is not going to perform the desired conversions. The default XmlAdapter expects the following to work:
Foo foo1 = new Foo(foo2.toString());
Which is not valid in this case:
Date date1 = new Date(date2.toString());
You will need to write some conversion code and reference it from an external bindings file:
<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
<jxb:bindings schemaLocation="format.xsd">
<jxb:bindings node="//xs:element[#name='my-date']">
<jxb:property>
<jxb:baseType>
<jxb:javaType name="java.util.Date"
parseMethod="org.example.DateFormatter.parseInt"
printMethod="org.example.DateFormatter.printInt" />
</jxb:baseType>
</jxb:property>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
For More Information
http://blog.bdoughan.com/2011/08/xml-schema-to-java-generating.html
I am trying to create a html based template with xslt transformation.The string result returned by the transformer is perfectly fine.but when i try to send it to display, the browser is not interpreting it. The output looks like<html><body>...</body></html>.
when i do view source it is displaying <html>... How can i resolve it?Please help.
Thanks in advance
Did you specify the output method correctly? It should be set to HTML:
<xsl:output method="html" encoding="UTF-8" />
<xsl:output value="html"/>
<xsl:template match="mail[#type='pinReset']">
<html><body>
<xsl:variable name="userService" select="java:new()"/>
<i><u>Message body </u><xsl:value-of select="mailMessage/mail/body/prefix"/></i>
<a><xsl:attribute name="href">
<xsl:value-of select="java:getResetPinUrl($userService)"/></xsl:attribute>
reset pin
</a>
<i><xsl:value-of select="mailMessage/body/suffix"/></i><br/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
This is my XSl.
public String getXformedString(int type){
String xFormedString = "";
String xsltFile = "D:\\SitesContent\\sitescontent_war\\JavaSource\\com\\tgt\\mobile\\gc\\controller\\email.xsl";
String xmlFile="D:\\SitesContent\\sitescontent_war\\JavaSource\\com\\tgt\\mobile\\gc\\controller\\emailBody.xml";
StringWriter stWr = new StringWriter();
File xsltfile = new File(xsltFile);
File xmlfile = new File(xmlFile);
Source xmlSource = new StreamSource(xmlfile);
Source xsltSource = new StreamSource(xsltfile);
Result result = new StreamResult(stWr);
TransformerFactory transFact = TransformerFactory.newInstance();
try {
Transformer transformer= transFact.newTransformer(xsltSource);
transformer.setParameter("type",new Integer(type));
transformer.transform(xmlSource, result);
xFormedString = stWr.toString();
System.out.println("Str->"+xFormedString);
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return xFormedString;
}
This is the code to get the formed string from xml and xslt.