I have a XML document.I am signing a part of document using xmlsignature. Before finding digest, I want to apply XSLT transform. According to what I read, XSLT converts an XML document to another format(can be XML also). Now I am confused that, where will be the transformed new document is avilable?How to retrieve the value from this newly created document if I want to show it to user?
My XML Document
<r1>
<user>asd</user>
<person>ghi</person>
</r1>
Code for Transformation
Transform t=fac.newTransform(Transform.XPATH,new XPathFilterParameterSpec("/r1/user"));
According to xpath transformation,Whenever value of user element changes the xmlsignature should not be validated. And if person element's value changes then Signature should be validated. But when I change person element's value the signature is not validated. WHY?
The xslt transform used when signing a document relates to how nodes in your source XML are selected when the signature is calculated.
This question/answer by Dave relates to signing parts of an XML document using xpath2. The link to Sean Mullans' post in this answer suggests xpath2 is more appropriate for signing parts of a document because the evaluation of an xpath expression is done per node.
So based on the sun dsig example you can replace the Reference creation using:
List<XPathType> xpaths = new ArrayList<XPathType>();
xpaths.add(new XPathType("//r1/user", XPathType.Filter.INTERSECT));
Reference ref = fac.newReference
("", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform(Transform.XPATH2,
new XPathFilter2ParameterSpec(xpaths))),
null, null);
This allows //r1/user to be protected with a signature while the rest of the document can be altered.
The problem with the xpath/xpath2 selection is that a signature can be generated for /some/node/that/does/not/exist. You are right to modify a test document and make sure the signature is working the way you expect.
You might test the document in a test program by generating a signature then tampering with the xml node before verification:
NodeList nlt = doc.getElementsByTagName("user");
nlt.item(0).getFirstChild().setTextContent("Something else");
A more reliable alternative to an xpath selector might be to put an ID on the xml document elements you hope to sign like:
<r1>
<user id="sign1">asd</user>
<person>ghi</person>
</r1>
then reference this ID as the URI in the first parameter of an enveloped transfer:
Reference ref = fac.newReference
("#sign1", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform(Transform.ENVELOPED,(TransformParameterSpec) null)),
null, null);
For the output, a signature operation adds a new Signature element to the DOM you have loaded in memory. You can stream the output by transforming it like this:
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.transform(new DOMSource(doc), new StreamResult(System.out));
The XSLT specification doesn't define what happens to the result document; that's defined by the API specifications of your chosen XSLT processor. For example, if you invoke XSLT from Java using the JAXP interface, you can ask for the result as a DOM tree in memory or for it to be serialized to a specified file on disk.
You have tagged your question "Java" which is the only clue you give to your processing environment. My guess is you want to transform to a DOM and then use DOM interfaces to get the value from the new document. Though if you're using XSLT 2.0 and Saxon, the s9api interface is much more usable than the native JAXP interface.
The xslt part defines only the transformation definition, nothing else.
Have a look at this:
java xslt tutorial
in Francois Gravel answer the input.xml file is the file that will be transformed, the transform.xslt is the xslt definition which describes how to transform the xml file. output.out are the results, this may be xml, but it can also be html, flat file...
This is where I started with when i was using xslt:
http://www.w3schools.com/xsl/default.asp
Have a look at this also:
http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog
Related
I'm trying to write an XSL that basically need to take some values from one xml and other from another and output a XML. I've searched online for some solution and I found that I've to put this <xsl:variable name='file' select="'file:///C:/Users/file.xml'"> inside my input XML which is supposed to load another XML and store it into a variable but from this I dont know how to get the tags value of the document.
The file.xml is this one
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<silosMediaObject>
<canBeDeleted>-1</canBeDeleted>
<checkedOut>-1</checkedOut>
<checkedOutBy>-1</checkedOutBy>
<deleted>-1</deleted>
<description>Traccia audio migrata da ASCN</description>
<externalResourcePath>TEST/ASCN/lq/3763_2015-05-05.mp3</externalResourcePath>
<fileName>3763_2015-05-05.mp3</fileName>
<framesPerSecond>-1</framesPerSecond>
<hasScheduledIngestion>false</hasScheduledIngestion>
<isArchived>-1</isArchived>
<isArchiving>-1</isArchiving>
<isAvailable>-1</isAvailable>
<isEncoding>-1</isEncoding>
<isRestoring>-1</isRestoring>
<isVerified>-1</isVerified>
<mediaObjectId>-1</mediaObjectId>
<mediaTypeId>-1</mediaTypeId>
<mosId>4347</mosId>
<resourceIsExternal>-1</resourceIsExternal>
<sourceMediaObjectId>-1</sourceMediaObjectId>
<state>AVAILABLE</state>
<versionLinkId>-1</versionLinkId>
</silosMediaObject>
The Java class I'm using to transform the file is this one:
public class TestMain {
public static void main(String[] args) throws IOException, URISyntaxException, TransformerException {
TransformerFactory factory = TransformerFactory.newInstance();
Source xslt = new StreamSource(new File("C:\\Users\\xmltemplate_transformer.xsl"));
Transformer transformer = factory.newTransformer(xslt);
Source text = new StreamSource(new File("C:\\Users\\tobe_transformed.xml"));
transformer.transform(text, new StreamResult(new File("C:\\Users\\out.xml")));
}
}
I've searched online for some solution and I found that I've to put this <xsl:variable name='file' select="'file:///C:/Users/file.xml'"> inside my input XML which is supposed to load another XML and store it into a variable
I don't know where you got that idea, but you're confused. The select value is interpreted as an XPath expression. Yours is a string literal containing a URL with the file scheme. As far as XPath or XSLT is concerned, it is just a string. One might do something further to cause the file designated by that URL to be parsed, but what you've presented has no such effect.
In particular, you might have wanted to do this:
<xsl:variable name='file' select="document('file:///C:/Users/file.xml')"/>
The document() function is the secret sauce that actually causes the designated file to be read and parsed (if possible); when used as shown, its result is a node set containing the root node of the resulting document, or an empty node set if the designated document cannot be parsed and the processor elects not to signal an error.
Note: when you say you put the xsl:variable "inside my input XML", I presume you mean at an appropriate place inside your (XML-based) XSL stylesheet. If you actually mean that you have placed it in a different XML data file that you are processing, then it will have no direct effect there, other than to be included, as itself, in the input tree.
but from this I dont know how to get the tags value of the document.
Having successfully parsed the file, you can use the resulting node set anywhere that XSLT expects an expression that evaluates to a node set. In particular, within its scope, you can use a reference to the variable you've defined ($file) as an argument to XPath functions, or as a whole expression, such as the select expression of an xsl:apply-templates. Since you haven't said what, specifically, you want to do with the contents, I cannot be any more specific myself. See what you can do, and if you can't figure out the details then that could be a suitable topic for a new question.
How can I transform multiple XML input document objects with a single XSL transformation script using the Saxon9HE processor in a Java application?
I found a way to transform multiple XML input files from the filesystem with an XSLT script here, but I can't figure out how to pass multiple loaded XML Document objects to a Java application utilizing the Saxon9HE API. For a single XML document my code looks like this and works:
Processor proc = new Processor(false);
XsltCompiler comp = proc.newXsltCompiler();
try {
XsltExecutable exp = comp.compile(new StreamSource(stylesheetFile));
XdmNode source = proc.newDocumentBuilder().build(new DOMSource(inputXML));
Serializer out = proc.newSerializer();
out.setOutputProperty(Serializer.Property.METHOD, "xml");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
out.setOutputFile(new File(outputFilename));
XsltTransformer trans = exp.load();
trans.setInitialContextNode(source);
trans.setDestination(out);
trans.transform();
} catch (SaxonApiException e) {
e.printStackTrace();
}
First point: avoid DOM if you can. When you are using Saxon, it's best to let Saxon build the document tree; this will be far more efficient. If you really need to use an external tree model, XOM and JDOM2 are much more efficient than DOM.
If you do want to provide a DOM as input, you have two choices: you can copy it to a Saxon tree, or you can wrap it as a Saxon tree. Use DocumentBuilder.build() in the first case, DocumentBuilder.wrap() in the second. Using build() gives you a higher initial cost, but the transformation itself is then faster.
If you want to pass pre-built trees into the transformation, declare the parameter using <xsl:param name="x" as="document-node()"/>, and then invoke the transformation using transformer.setParameter(new QName('x'), doc) where doc is an instance of XdmNode. You have to construct the XdmNode yourself by using a DocumentBuilder.
(Alternatively, if you want to access the documents in the stylesheet using the doc() or document() functions, you can invent a URI naming scheme and implement this in a URIResolver. When doc('my:uri') is called, your URIResolver is notified, and it should respond with a Source object. If you already have an XdmNode handy, then you can return XdmNode.asSource() to return this document tree as the result of your URIResolver.)
This code is in Java and uses Saxon
I am implementing a transform function to transform xml and several secondary xml sources
All of the inputs are not files, so I cannot use document() or other methods that define files directly
String transform(String xml, List<String> secondaryXmls, String xslt);
It outputs the transformed xml result
I am successful in applying the transformation from xslt to the single xml file, but I have difficulties in applying transformation that also utilize the secondaryXmls. I have done my research and still could not find the right method to apply these
here is a snapshot of the code
TransformerFactory tFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl",null);
Document transformerDoc = loadXMLFromString(xslt);
Source transformerSource = new DOMSource(transformerDoc);
Transformer transformer = tFactory.newTransformer(transformerSource);
Document sourceDoc = loadXMLFromString(xml);
Source source = new DOMSource(sourceDoc);
DOMResult result = new DOMResult();
transformer.transform(source, result);
Document resultDoc = (Document) result.getNode();
return getStringFrom(resultDoc);
Thanks!
EDIT:
Which is the better way:
concatenating all the xmls, transform, return only the original part filtering the concatenated secondary xmls
Write a code that adds
<xsl:variable name="asd" select="document('asd')">
on top of the xslt string
First thing - get rid of all that DOM stuff! Using the DOM with Saxon slows it down by a factor of ten. Let Saxon build the trees in its own format, by using a StreamSource or SAXSource, and a StreamResult. Or you can build a tree in Saxon format yourself, if you want, using the s9api DocumentBuilder class.
Then as to the answer to your question: here are three possible solutions:
(a) supply the documents as a stylesheet parameter of type document-node()* (that is, a sequence of document nodes). In the Java, convert your list of XML strings to a list of document nodes by calling Configuration.buildDocument() on each one.
(b) write a URIResolver whose effect is to interpret the URI doc/3 as meaning the third document in the list; then use document('doc/3') to fetch that document.
(c) write a CollectionURIResolver which makes the whole collection of documents available using the collection() function.
I have to write some code to handle reading and validating XML documents that use a version attribute in their root element to declare a version number, like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Junk xmlns="urn:com:initech:tps"
xmlns:xsi="http://www3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:com:initech.tps:schemas/foo/Junk.xsd"
VersionAttribute="2.0">
There are a bunch of nested schemas, my code has an org.w3c.dom.ls.LsResourceResolver to figure out what schema to use, implementing this method:
LSInput resolveResource(String type,
String namespaceURI,
String publicId,
String systemId,
String baseURI)
Previous versions of the schema have embedded the schema version into the namespace, so I could use the namespaceURI and systemId to decide which schema to provide. Now the version number has been switched to an attribute in the root element, and my resolver doesn't have access to that. How am I supposed to figure out the version of the XML document in the LsResourceResolver?
I had never had to deal with schema versions before this and had no idea what was involved. When the version was part of the namespace then I could throw all the schemas in together and let them get sorted out, but with the version in the root element and namespace shared across versions there is no getting around reading the version information from the XML before starting the SAX parsing.
I'm going to do something very similar to what Pangea suggested (gets +1 from me), but I can't follow the advice exactly because the document is too big to read it all into memory, even once. By using STAX I can minimize the amount of work done to get the version from the file. See this DeveloperWorks article, "Screen XML documents efficiently with StAX":
The screening or classification of XML documents is a common problem,
especially in XML middleware. Routing XML documents to specific
processors may require analysis of both the document type and the
document content. The problem here is obtaining the required
information from the document with the least possible overhead.
Traditional parsers such as DOM or SAX are not well suited to this
task. DOM, for example, parses the whole document and constructs a
complete document tree in memory before it returns control to the
client. Even DOM parsers that employ deferred node expansion, and thus
are able to parse a document partially, have high resource demands
because the document tree must be at least partially constructed in
memory. This is simply not acceptable for screening purposes.
The code to get the version information will look like:
def map = [:]
def startElementCount = 0
def inputStream = new File(inputFile).newInputStream()
try {
XMLStreamReader reader =
XMLInputFactory.newInstance().createXMLStreamReader(inputStream)
for (int event; (event = reader.next()) != XMLStreamConstants.END_DOCUMENT;) {
if (event == XMLStreamConstants.START_ELEMENT) {
if (startElementCount > 0) return map
startElementCount += 1
map.rootElementName = reader.localName
for (int i = 0; i < reader.attributeCount; i++) {
if (reader.getAttributeName(i).toString() == 'VersionAttribute') {
map.versionIdentifier = reader.getAttributeValue(i).toString()
return map
}
}
}
}
} finally {
inputStream.close()
}
Then I can use the version information to figure out what resolver to use and what schema documents to set on the SaxFactory.
My Suggestion
Parse the Document using SAX or DOM
Get the version attribute
Use the Validator.validate(Source) method and and use the already parsed Document (from step 1) as shown below
Building DOMSource from parsed document
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(args[0]));
domSource = new DOMSource(document);
i'm doing a java project about digital signature on microsoft office files (docx, xlsx, pptx).
i can create an object which will be added in the xml signature using:
XMLSignatureFactory xml_fac = XMLSignatureFactory.newInstance("DOM");
XMLObject xml_object = XMLSignatureFactory.newXMLObject(...
ArrayList<XMLObject> obj_list = new ArrayList<XMLObject>();
obj_list.add(xml_object);
XMLSignature xml_sig = xml_fac.newXMLSignature(...,...,obj_list,...
however, this xml signature generated by java doesn't
contain xmlns for the type XMLObject
for microsoft office to recognise this xml object:
<Object>
<SignatureProperties>
<SignatureProperty Id="idSignatureTime" Target="#idPackageSignature">
<mdssi:SignatureTime>
<mdssi:Format>YYYY-MM-DDThh:mm:ssTZD</mdssi:Format>
<mdssi:Value>2011-04-02T10:10:10Z</mdssi:Value>
</mdssi:SignatureTime>
</SignatureProperty>
</SignatureProperties>
</Object>
i have to add:
xmlns:mdssi="http://schemas.openxmlformats.org/package/2006/digital-signature"
into the opening <Object> tag
but XMLObject in java has no way to add this, it has only Id, MimeType, Encoding, and Content
any suggestions?
SignatureProperty property = XML_SIGNATURE_FACTORY.newSignatureProperty(
...);
SignatureProperties properties = XML_SIGNATURE_FACTORY.newSignatureProperties(
Collections.singletonList(property), ...);
XMLObject object = XML_SIGNATURE_FACTORY.newXMLObject(
Collections.singletonList(properties), ...);
Version 2:
Here comes story. I uses Java. (JSR-105)
I'm digging XML Digital Signature for W3C Widgets.
for Signature/Object
-- It seems easy first time I saw the APIs. I just created XMLObject like above.
But, as spec says, I have to insert a Reference referring the XMLObject created by 1.
-- What? How can I make a reference referring an output node?
-- How can I return a Data for Nodes not even created yet?
I realized that I should prepare a org.w3c.dom.Document containing the <Object> element (and its children as purposed) and use it for the Reference.
--> With your URIDereferencer, you can return a NodeSetData from this document's getDocumentElement() result.
So here comes the solution.
Make a org.w3c.dom.Document instance containing the <Object> element as its root element. You can add any attributes and child elements as you wish.
And you can generate an XML Signature as detached or enveloping scheme.
Check this out. This is where I found the solution. And I think your problem will be solved.
http://today.java.net/pub/a/today/2006/11/21/xml-signature-with-jsr-105.html#generate-an-enveloping-signature
Sorry for my poor English. I'm Korean. :)
My best regards.
Jin Kwon