我正在使用componentDidMount
API进行XSL转换。该API仅允许一个XML文档作为输入来应用如下所示的转换。
javax.xml.transform
还可以通过如下所示的简单String参数,而不会出现以下任何问题:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
StringWriter stringWriter = new StringWriter();
File xml = new File("C:\\abc");
File xsl = new File("C:\\def.xsl");
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(xml);
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
StreamSource style = new StreamSource(xsl);
Transformer transformer = transformerFactory.newTransformer(style);
DOMSource source = new DOMSource(document);
但是,我想将XML文档作为参数传递给XSL文件。我尝试在SO页面之一上建议以下代码,如下所示:
transformer.setParameter("mode", "CREATE");
然后我将XML标记设置为接收值,如下所示:
DocumentBuilder builder = factory.newDocumentBuilder();
final Document documentFile = builder.parse(xml2);
Map<String, Document> docs = new HashMap<String, Document>();
docs.put("lookup", documentFile);
transformer.setURIResolver(new DocumentURIResolver(docs));
但是它对我不起作用。有人可以帮助我以正确的方式帮助我通过javax.xml.transform API将多个XML文档传递到任何XSL文件吗?
更新
问题仍然存在,任何人都可以让我如何将XML对象作为参数传递给XSLT 2.0样式表。我尝试了不同的方法,但是仍然没有运气。我需要通过JAVA xsl转换API了解出路。
答案 0 :(得分:1)
(答案已扩展为可以处理通过URIResolver传递的已解析W3C DOM文档)
这可以使用JRE随附的Xalan XSLT处理器版本在纯XSLT / XPath中完成。
例如,假设输入文档之一的名称是否作为参数传递给 T(n) = 3T(n/3) + cn
= T(3^k) = 3T(3^(k-1)) + 3^k
= 3(3T(3^(k-2)) + 3^(k-1)) + 3^k
= 3^2T(3^(k-2)) + 3^k + 3^k
= 3^2(3T(3^(k-3)) + 3^(k-2)) + 3^k + 3^k
= 3^3T(3^(k-3)) + 3^k + 3^k + 3^k
= ...
= 3^kT(1) + k*3^k
= nT(1) + n*log3n
= n + n*log3n
:
n = n
n/3 n/3 n/3 = n
n/9 n/9 n/9 n/9 n/9 n/9 n/9 n/9 n/9 = n
... = n
然后可以按如下所示将此参数传递到XPath中的Transformer
函数中:
File parentDir = new File("c:\\dir");
StringWriter stringWriter = new StringWriter();
File xml = new File(parentDir, "input.xml");
File xsl = new File(parentDir, "xslt-document-param.xslt");
Source xsltSource = new StreamSource(xsl);
Source xmlSource = new StreamSource(xml);
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer(xsltSource);
transformer.setParameter("doc-name", "basic.xml");
transformer.transform(xmlSource, new StreamResult(stringWriter));
System.out.println(stringWriter);
这能够(通过参数)读取此document()
:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan"
version="1.0"
exclude-result-prefixes="xalan">
<xsl:output
method="xml"
indent="yes"
xalan:indent-amount="2"/>
<xsl:param name="doc-name"/>
<xsl:template match="/">
<xsl:variable name="doc-content" select="document($doc-name)"/>
<parent>
<xsl:for-each select="$doc-content/basic/*">
<child>
<xsl:value-of select="name(.)"/>
</child>
</xsl:for-each>
</parent>
</xsl:template>
</xsl:stylesheet>
并将其转换为:
basic.xml
<basic>
<one/>
<two/>
<three/>
</basic>
函数的参数是URI。相对路径是相对于XSL文件解析的。同样,这可以是完整的URL,也可以通过问题中的自定义<parent>
<child>one</child>
<child>two</child>
<child>three</child>
</parent>
来解决。
(从此处编辑...)
要使用将预先解析的document()
对象传递给XSLT的方法,transformer.setURIResolver()
方法能够处理将其传递回Document
函数的作用。
例如,在问题中进行查找:
URIResolver
此XSL能够通过与上述相同的document()
进行迭代...
File lookupXml = new File(parentDir, "basic.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(lookupXml);
Map<String, Document> docs = new HashMap<>();
docs.put("lookup", document);
transformer.setURIResolver((href, base) -> new DOMSource(docs.get(href)));
...并输出相同的结果。
答案 1 :(得分:1)
我认为您的问题出在XSLT中。更改
<xsl:variable name="lookup" select="('documentFile')/> .
到
<xsl:variable name="lookup" select="document('lookup')/>
这将导致转换器在变量DOM
中访问文档的lookup
。密钥lookup
来自docs.put("lookup", documentFile);
完整的示例:
有3个XML文件:repo.xml
,books.xml
和articles.xml
。 repo.xml
包含有关书籍和文章的状态信息。文件articles.xml
和books.xml
包含有关每个项目的标题信息。目的是打印所有书籍和文章的状态信息以及标题信息。所有文件中的条目都通过id
键进行连接。
在github找到完整的示例,或复制/粘贴以下列表。
repo.xml
<repository>
<book>
<id>1</id>
<status>available</status>
</book>
<book>
<id>2</id>
<status>lost</status>
</book>
<article>
<id>1</id>
<status>in transit</status>
</article>
</repository>
books.xml
<books>
<book id="1">
<title>Book One</title>
</book>
<book id="2">
<title>Book Two</title>
</book>
<book id="3">
<title>Book Three</title>
</book>
</books>
articles.xml
<articles>
<article id="1">
<title>Article One</title>
</article>
<article id="2">
<title>Article Two</title>
</article>
<article id="3">
<title>Article Three</title>
</article>
</articles>
join.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<titleStatusJoin>
<xsl:for-each select="//book">
<xsl:variable name="myId" select="id" />
<book>
<status>
<xsl:value-of select="status" />
</status>
<title>
<xsl:for-each select="document('bookFile')//book">
<xsl:variable name="bookId" select="@id" />
<xsl:choose>
<xsl:when test="$myId = $bookId">
<xsl:value-of select="title" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</title>
</book>
</xsl:for-each>
<xsl:for-each select="//article">
<xsl:variable name="myId" select="id" />
<article>
<status>
<xsl:value-of select="status" />
</status>
<title>
<xsl:for-each select="document('articleFile')//article">
<xsl:variable name="bookId" select="@id" />
<xsl:choose>
<xsl:when test="$myId = $bookId">
<xsl:value-of select="title" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</title>
</article>
</xsl:for-each>
</titleStatusJoin>
</xsl:template>
</xsl:stylesheet>
使用此Java代码...
@Test
public void useMultipleXmlSourcesInOneXsl3() {
InputStream xml = Thread.currentThread().getContextClassLoader().getResourceAsStream("stack54335576/repo.xml");
InputStream xsl = Thread.currentThread().getContextClassLoader().getResourceAsStream("stack54335576/join3.xsl");
InputStream booksXml = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("stack54335576/books.xml");
InputStream articlesXml = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("stack54335576/articles.xml");
Document booksDom = readXml(booksXml);
Document articlesDom = readXml(articlesXml);
Map<String, Document> parameters = new HashMap<>();
parameters.put("bookFile", booksDom);
parameters.put("articleFile", articlesDom);
xslt(xml, xsl, parameters);
}
public final void xslt(InputStream xml, InputStream xsl, Map<String, Document> parameters) {
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xsl));
transformer.setURIResolver((href, base) -> new DOMSource(parameters.get(href)));
transformer.transform(new StreamSource(xml), new StreamResult(System.out));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Document readXml(InputStream xmlin) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(xmlin);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
...产生此输出
<?xml version="1.0" encoding="UTF-8"?>
<titleStatusJoin>
<book>
<status>available</status>
<title>Book One</title>
</book>
<book>
<status>lost</status>
<title>Book Two</title>
</book>
<article>
<status>in transit</status>
<title>Article One</title>
</article>
</titleStatusJoin>
答案 2 :(得分:0)
不确定您的问题,如果您提供用例并询问如何解决将更有益于询问如何修复您的代码,因为我们没有端到端地看到您的代码和xml。
以下可能是解决方案:
1)我们可以将xml转换为字符串
try {
StringReader _reader = new StringReader("<xml>vkhan</xml>");
StringWriter _writer = new StringWriter();
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(
new javax.xml.transform.stream.StreamSource("styler.xsl"));//ur xsl
transformer.transform(
new javax.xml.transform.stream.StreamSource(_reader),
new javax.xml.transform.stream.StreamResult(_writer));
String result = writer.toString();
} catch (Exception e) {
e.printStackTrace();
}
2)根据您的要求修改以下代码,作为for循环中的调用对象列表。
public class Data {
public static final Document transformXmlDocument(Document sourceDocument, InputStream xsltFile) {
DOMSource xmlSource = new DOMSource(sourceDocument);
StreamSource xsltSource = new StreamSource(xsltFile);
Document transformedData = null;
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xsltSource);
ByteArrayOutputStream output = new ByteArrayOutputStream();
StreamResult result = new StreamResult(output);
transformer.transform(xmlSource, result);
DocumentBuilder resultBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
transformedData = resultBuilder.parse(
new InputSource(
new StringReader(
new String(output.toByteArray())
)
)
);
} catch (Exception e) {
Log.e("XSLT Transformation", e.getMessage());
}
return transformedData;
}
}
答案 3 :(得分:0)
尝试将<xsl:variable name="lookup" select="('documentFile')"/>
的指令替换为<xsl:variable name="documentFile" select="document($lookup)"/>
,并将XML文档作为参数传递给transformer.setParameter("lookup", "myfile.xml");
,这意味着:将lookup参数引用的文档加载到{{1} }变量。
答案 4 :(得分:0)
您已经尝试过吗?
org.w3c.dom.Document doc = ... // Your xml document
transformer.setParameter("demo", doc.getDocumentElement());