如何在XML中的XSL转换中包含命名空间

时间:2017-01-25 12:23:36

标签: java xml xslt namespaces xslt-1.0

我正在尝试使用JAVA将xml文件转换为另一个xml文件。转换后,新的xml将具有一组子元素和所需的命名空间。但是,我无法包含特定的必需命名空间。它是全部或全部。有人可以帮忙吗?

输入XML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:root 
    xmlns="http://uri1.com" 
    xmlns:ns2="http://uri2.com">
    <element1>
        <elementA1>
            <elementB1>AA</elementB1>            
        </elementA1>
        <elementA2>12345</elementA2>
        <elementA3>A 000</elementA3>
     </element1>
</ns2:root>

预期输出XML

<?xml version="1.0" encoding="UTF-8"?>
    <element1 xmlns="http://uri1.com" >
        <elementA1>
            <elementB1>AA</elementB1>            
        </elementA1>
        <elementA2>12345</elementA2>
        <elementA3>A 000</elementA3>
     </element1>

我正在使用的XSL文件

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- <xsl:output method="xml" omit-xml-declaration="yes" encoding="utf-8"/> -->

  <!-- For each element, create a new element with the same local-name (no namespace) -->
  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:copy-of select="@*"/> 
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

  <!-- Skip the root element, just process its children. -->
  <xsl:template match="/*">
    <xsl:apply-templates/>
  </xsl:template>

</xsl:stylesheet>

当前输出XML(没有名称空间)

<?xml version="1.0" encoding="UTF-8"?>
    <element1>
        <elementA1>
            <elementB1>AA</elementB1>            
        </elementA1>
        <elementA2>12345</elementA2>
        <elementA3>A 000</elementA3>
     </element1>

用于执行XSL转换的Java代码

import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public final class XsltTransformer {

  private Templates templates;

  public XsltTransformer(final String xslFilePath) {
    String xslt = FileUtils.getAsString(xslFilePath);
    try {
      this.templates = TransformerFactory.newInstance().newTemplates(new StreamSource(new StringReader(xslt)));
    } catch (Exception e) {
      throw new IllegalArgumentException("Error while creating XLST transformer with XSLT text [" + xslt + "]", e);
    }
  }

  public String applyTransformation(final String inputXml) {
    try {
      StreamSource in = new StreamSource(new StringReader(inputXml));
      StreamResult out = new StreamResult(new StringWriter());     
      templates.newTransformer().transform(in, out);
      return out.getWriter().toString();
    } catch (Exception e) {
      throw new IllegalArgumentException("Unable to transform input XML [" + inputXml + "]", e);
    }
  }

}

有人可以帮助我在预期的输出XML中添加特定的命名空间吗? 谢谢!

4 个答案:

答案 0 :(得分:2)

所以最后我找到了一种通过使用默认命名空间来破解结果的方法。以上所有答案都运行正常,这也适用于Java Transformation。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:ns1="http://uri1.com" 
    xmlns:ns2="http://uri2.com">
  <!-- For each element, create a new element with the same local-name (no namespace) -->
  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:copy-of select="@*"/> 
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

  <!-- Skip the root element, just process its children. -->
  <xsl:template match="/*">
    <xsl:apply-templates/>
  </xsl:template>

  <!--override the new root element and insert the default namespace -->
  <xsl:template match="/ns2:root/ns1:element1">
        <xsl:element name="element1"
            xmlns="http://uri1.com">
            <xsl:apply-templates select="@* | node()" />
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

在样式表标记中,将默认名称空间声明为:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://uri1.com">

答案 2 :(得分:1)

只需删除根包装器即可实现所需的结果:

XSLT 1.0

xmlns:ns2="http://uri2.com"

请注意,这将留下冗余的命名空间声明function CurrenciesService($http, $q) { return { getCurrencies: function () { var rates = []; var urls = [{url: 'https://api.nbp.pl/api/exchangerates/rates/c/usd/today/'}, {url: 'https://api.nbp.pl/api/exchangerates/rates/c/eur/today/'}, {url: 'https://api.nbp.pl/api/exchangerates/rates/c/gbp/today/'}]; var urlsCalls = []; angular.forEach(urls, function (url) { urlsCalls.push($http.get(url.url)); }); return $q.all(urlsCalls) .then(function (result) { angular.forEach(result, function (rate) { var currency = {}; currency.code = rate.data.code; currency.sell = rate.data.rates[0].bid; currency.buy = rate.data.rates[0].ask; currency.date = rate.data.rates[0].effectiveDate; rates.push(currency); }); return rates; }); } }; } ,但除非您的目标应用程序不符合,否则这不应该是一个问题。

答案 3 :(得分:1)

这是一个转换,可以准确地给出您期望的结果。

在样式表中,如果需要查找特定元素,则必须重新声明输入文档中存在的命名空间。然后,您可以使用前缀引用名称空间中的元素,例如ns1:

使用xsl:element构建新元素时,可以添加属性namespace,这将为新元素生成默认命名空间

<强>样式表

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:ns2="http://uri2.com">

  <xsl:strip-space elements="*"/>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="*">
    <xsl:element name="{local-name()}" namespace="http://uri1.com">
      <xsl:copy-of select="@*"/> 
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="/ns2:root">
      <xsl:apply-templates/>
  </xsl:template>

</xsl:stylesheet>

XML输出

<?xml version="1.0" encoding="UTF-8"?>
<element1 xmlns="http://uri1.com">
   <elementA1>
      <elementB1>AA</elementB1>
   </elementA1>
   <elementA2>12345</elementA2>
   <elementA3>A 000</elementA3>
</element1>

在线试用here