当前位置: 首页 > 面试题库 >

保留名称空间前缀定义的同时从XML文档中提取元素

公羊雅达
2023-03-14
问题内容

我正在尝试从XML文档中提取元素(作为字符串)。我已经尝试过此SO答案中建议的两种方法(此处也建议使用类似的方法),但它们都无法正确考虑可能在某些外部文档中定义的名称空间前缀。

使用以下代码:

// entry point method; see exampes of values for the String `s` in the question
public static String stripPayload(String s) throws Exception {
    final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    final Document doc = dbf.newDocumentBuilder().parse(new InputSource(new StringReader(s)));

    final XPath xPath = XPathFactory.newInstance().newXPath();
    final String xPathToGetToTheNodeWeWishToExtract = "/*[local-name()='envelope']/*[local-name()='payload']";
    final Node result = (Node) xPath.evaluate(xPathToGetToTheNodeWeWishToExtract, doc, XPathConstants.NODE);
    return nodeToString_A(result); // or: nodeToString_B(result)

}

public static String nodeToString_A(Node node) throws Exception {
    final StringWriter buf = new StringWriter();
    final Transformer xform = TransformerFactory.newInstance().newTransformer();
    xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
    xform.setOutputProperty(OutputKeys.STANDALONE, "yes");
    xform.transform(new DOMSource(node), new StreamResult(buf));
    return(buf.toString());
}

public static String nodeToString_B(Node node) throws Exception {
    final Document document = node.getOwnerDocument();
    final DOMImplementationLS domImplLS = (DOMImplementationLS) document.getImplementation();
    final LSSerializer serializer = domImplLS.createLSSerializer();
    final String str = serializer.writeToString(node);
    return str;
}

如果该stripPayload方法如果传递了以下字符串:

<envelope><payload><a></a><b></b></payload></envelope>

要么

<envelope><p:payload xmlns:p='foo'><a></a><b></b></p:payload></envelope>

......都nodeToString_AnodeToString_B方法的工作。但是,如果我传递以下同样有效的XML文档,其中在外部元素中定义了名称空间前缀:

<envelope xmlns:p='foo'><p:payload><a></a><b></b></p:payload></envelope>

…然后,这两种方法都会失败,因为它们只是发出:

<p:payload><a/><b/></p:payload>

因此,由于忽略了名称空间前缀定义,他们已经在生成无效的文档。

下面更复杂的示例(在属性中使用名称空间前缀):

<envelope xmlns:p='foo' xmlns:a='alpha'><p:payload a:attr='dummy'><a></a><b></b></p:payload></envelope>

……实际上导致nodeToString_A失败并带有异常,而至少nodeToString_B会产生无效:

<p:payload a:attr="dummy"><a/><b/></p:payload>

(同样,前缀未定义)。

所以我的问题是:

什么是一种健壮的方法来提取内部XML元素并对其进行字符串化,从而处理可能在某些外部元素中定义的名称空间前缀?


问题答案:

您只需要启用 name-space-awareness即可

public static String stripPayload(String s) throws Exception {
    final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);

    ...
}

输出将是…

<p:payload xmlns:p="foo"><a/><b/></p:payload>


 类似资料:
  • 我有一个有趣的情况,我的XML编辑器(Oxygen,使用Xerces XML处理器)需要根标签上的前缀,但是我的JAXB XML Marshaller(也是基于Xerces的)不需要根标签上的前缀。我正在试图理解这种情况。 首先是2个模式文件: ns1.xsd ns2。xsd 目前的氧气释放(16.1)需要我称之为“版本1”的东西 版本1 如果我像下面的示例(版本1)那样删除前缀: 版本2 氧气抱

  • 使用xslt 1.0(BizTalk 2016)我正在寻找一种通用的方法来选择任何有效的xml文档的命名空间 例如,我有以下xml文档: 假设根元素的值可以是任何东西,那么选择名称空间值的xpath是什么http://www.random.com/bo/request/portfolioactivation 我原本希望“/*/@xmlns”能起作用,但事实并非如此。

  • 我想知道是否有一种方法来强制JAXB创建与XSD模式相同的名称空间前缀。即,即使我从一个包含xmlns:cts=“http://cts.com”的模式创建JAXB类,在封送类之后,我得到一个具有xmlns:ns1前缀的XML。我知道我可以通过使用NamespacePrefixMapper类来重写这些,但是为什么我需要在我的XSD明确定义了默认前缀的情况下手动执行此操作呢?在我当前的XML中有大量的

  • 问题内容: 除了包级别注释外,还有其他方法可以使用注释来控制自定义名称空间前缀。 可以在元素级别完成吗?也可能有一个带有多个前缀的名称空间吗? 问题答案: 您实际上想做什么?为什么名称空间前缀对您很重要? 对于命名空间前缀,没有标准的元素级注释。 我知道的控制名称空间前缀的选项是: 你已经提到过。 提供习俗。 XML的低级处理(例如,在StAX,SAX或DOM级别)。 我也可以想象: / 通常使用

  • 面临使用JAXB解组的问题。我需要使用多个名称空间。Java类是为第三方提供的XSD生成的。因此,我不想在Java类中的XMLRootElement指定名称空间,也不想手动更改多个类。 编组逻辑如下: xmlelement类TokenRequest.java BasicInRequestType.java 我在package-info.java中指定了前缀 TokenRequest元素实际上引用了

  • 问题内容: 我有一个需要打开并进行一些更改的xml文件,其中之一是删除名称空间和前缀,然后保存到另一个文件。这是xml: 我可以进行所需的其他更改,但是找不到如何删除名称空间和前缀的方法。这是我需要的reusklt xml: 这是我的脚本,它将打开并解析xml并将其保存: 那么,如何在脚本中添加代码以删除名称空间和前缀呢? 问题答案: 按照Uku Loskit的建议替换标签。除此之外,请使用lxm