Trying to use XInclude with Java and resolving the fragment with xml:id

a 夏天 提交于 2020-01-24 20:00:12

问题


I've been trying to get XInclude working in my XML document and finally have it working in Oxygen XML, which I'm using to author the XML documents.

I then went to my app, written in Java, but it doesn't seem to support any form of XPointer resolution except using something like: element(/1/2).

This is, obviously, an awful scheme to have to use since every time the document is edited the XPointer needs changing to reflect the new position of the node in the XML!

The scheme I had working simply used xml:id in the target document:

<foo>
    <bar xml:id="ABCD" />
</foo>

and then, in the other document:

<lorem>
    <ipsum>
         <xi:include href="target.xml" xpointer="ABCD" />
    </ipsum>
</lorem>

Which I anticipate (and am getting in Oxygen) results in something like:

<lorem>
    <ipsum>
         <bar xml:id="ABCD" />
    </ipsum>
</lorem>.

However, in Java it fails with:

Resource error reading file as XML (href='data/target.xml'). Reason: XPointer resolution unsuccessful.

If, however, I change the include tag to use

xpointer="element(/1/1)"

then it works very nicely - but, as I've said, that's a very poor solution.

I'm simply using the implementations that are included with the Java runtime (1.8).

Here's the code I'm using:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setXIncludeAware(true);
Source resultSource = new 
StreamSource(Gdx.files.internal("data/result.xsd").read());
            Source targetSource = new 
StreamSource(Gdx.files.internal("data/target.xsd").read());
            Source[] schemaFiles = {targetSource, resultSource};
            schema = 
SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema")
                    .newSchema(schemaFiles);
            factory.setSchema(schema);
            builder = factory.newDocumentBuilder();
            itemDoc = builder.parse(new 
InputSource(Gdx.files.internal("data/result.xml").read()));

回答1:


According to Apache Xerces's docs on XInclude (which is used internally for XML parsing by Java)

for shorthand pointers and element() XPointers, currently only DTD-determined IDs are supported.

This means that you need to put markup declarations such as the following into your target.xml file (telling the XML parser that the id attribute is to be treated as attribute with ID semantics, and telling XInclude to interpret "bare" XPointers as ID references):

<!DOCTYPE foo [
  <!ATTLIST bar id ID #IMPLIED>
]>
<foo>
    <bar id="ABCD"/>
</foo>

If you now use the following document as your source XML (which you've named result.xml in your example code, and which I've edited to contain an XInclude namespace URI binding for xi)

<lorem xmlns:xi="http://www.w3.org/2001/XInclude">
  <ipsum>
    <xi:include href="target.xml" xpointer="ABCD"/>
  </ipsum>
</lorem>

then Xerces will build up a Document where XInclude processing has been performed as desired (where i've put your example data into the target.xml file in the same directory as the result.xml file):

<lorem xmlns:xi="http://www.w3.org/2001/XInclude">
  <ipsum>
    <bar id="ABCD" xml:base="target.xml"/>
  </ipsum>
</lorem>

The Java code I've used to produce the document is simplified from your example and doesn't contain third-party libs:

import java.io.*;
import javax.xml.*;
import javax.xml.parsers.*;
import javax.xml.validation.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import org.w3c.dom.*;

public class t {

  public static void main(String[] args) {
    try {
      DocumentBuilderFactory factory =
        DocumentBuilderFactory.newInstance();
      factory.setNamespaceAware(true);
      factory.setXIncludeAware(true);
      DocumentBuilder builder = factory.newDocumentBuilder();
      Document itemDoc = builder.parse(new File("result.xml"));
      System.out.println(serialize(itemDoc));
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  static String serialize(Document doc) throws Exception {
    Transformer transformer =
      TransformerFactory.newInstance().newTransformer();
    StreamResult result = new StreamResult(new StringWriter());
    DOMSource source = new DOMSource(doc);
    transformer.transform(source, result);
    return result.getWriter().toString();
  }
}

Seeing as you also use XML Schema validation, I'd also like to point out the potential interaction of XInclude with XML Schema as eg. discussed in XInclude Schema/Namespace Validation?, and also a potential alternative discussed in Duplicate some parts of XML without rewriting them .



来源:https://stackoverflow.com/questions/50294372/trying-to-use-xinclude-with-java-and-resolving-the-fragment-with-xmlid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!