Skip to content

Commit

Permalink
Hyperlink to open declared DTD files
Browse files Browse the repository at this point in the history
Fixes #641

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Apr 17, 2020
1 parent 24cd010 commit 5883cae
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Angelo ZERR.
* Copyright (c) 2018-2020 Angelo ZERR.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -305,7 +305,7 @@ private NoNamespaceSchemaLocation createNoNamespaceSchemaLocation(DOMNode root,
if (attr == null || attr.getValue() == null) {
return null;
}
return new NoNamespaceSchemaLocation(root.getOwnerDocument().getDocumentURI(), attr);
return new NoNamespaceSchemaLocation(attr);
}

// -------------------------- Grammar with DTD
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,15 @@
*/
package org.eclipse.lemminx.dom;

import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.util.URI.MalformedURIException;

/**
*
* The declared "xsi:noNamespaceSchemaLocation"
*/
public class NoNamespaceSchemaLocation {

private final String documentURI;

private final DOMAttr attr;

public NoNamespaceSchemaLocation(String documentURI, DOMAttr attr) {
this.documentURI = documentURI;
public NoNamespaceSchemaLocation(DOMAttr attr) {
this.attr = attr;
}

Expand All @@ -45,21 +39,4 @@ public String getLocation() {
return attr.getValue();
}

/**
* Returns the expanded system location
*
* @return the expanded system location
*/
public String getResolvedLocation() {
return getResolvedLocation(documentURI, getLocation());
}

private String getResolvedLocation(String documentURI, String location) {
try {
return XMLEntityManager.expandSystemId(location, documentURI, false);
} catch (MalformedURIException e) {
return location;
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Angelo ZERR
* Copyright (c) 2018-2020 Angelo ZERR
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -14,31 +14,81 @@

import java.util.List;

import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.util.URI.MalformedURIException;
import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMDocumentType;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lemminx.dom.DOMRange;
import org.eclipse.lemminx.dom.NoNamespaceSchemaLocation;
import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant;
import org.eclipse.lsp4j.DocumentLink;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;

/**
* Document link for :
*
* <ul>
* <li>XML Schema xsi:noNamespaceSchemaLocation</li>
* <li>DTD SYSTEM (ex : <!DOCTYPE root-element SYSTEM "./extended.dtd" )</li>
* </ul>
*
* @author Angelo ZERR
*
*/
public class ContentModelDocumentLinkParticipant implements IDocumentLinkParticipant {

@Override
public void findDocumentLinks(DOMDocument document, List<DocumentLink> links) {
// Document link for xsi:noNamespaceSchemaLocation
NoNamespaceSchemaLocation noNamespaceSchemaLocation = document.getNoNamespaceSchemaLocation();
if (noNamespaceSchemaLocation != null) {
try {
String location = noNamespaceSchemaLocation.getResolvedLocation();
DOMNode attrValue = noNamespaceSchemaLocation.getAttr().getNodeAttrValue();
Position start = document.positionAt(attrValue.getStart() + 1);
Position end = document.positionAt(attrValue.getEnd() - 1);
links.add(new DocumentLink(new Range(start, end), location));
String location = getResolvedLocation(document.getDocumentURI(),
noNamespaceSchemaLocation.getLocation());
if (location != null) {
DOMNode attrValue = noNamespaceSchemaLocation.getAttr().getNodeAttrValue();
Position start = document.positionAt(attrValue.getStart() + 1);
Position end = document.positionAt(attrValue.getEnd() - 1);
links.add(new DocumentLink(new Range(start, end), location));
}
} catch (BadLocationException e) {
// Do nothing
}
}
// Document link for DTD
DOMDocumentType docType = document.getDoctype();
if (docType != null) {
String location = getResolvedLocation(document.getDocumentURI(), docType.getSystemIdWithoutQuotes());
if (location != null) {
try {
DOMRange sytemIdRange = docType.getSystemIdNode();
Position start = document.positionAt(sytemIdRange.getStart() + 1);
Position end = document.positionAt(sytemIdRange.getEnd() - 1);
links.add(new DocumentLink(new Range(start, end), location));
} catch (BadLocationException e) {
// Do nothing
}
}
}
}

/**
* Returns the expanded system location
*
* @return the expanded system location
*/
private static String getResolvedLocation(String documentURI, String location) {
if (location == null) {
return null;
}
try {
return XMLEntityManager.expandSystemId(location, documentURI, false);
} catch (MalformedURIException e) {
return location;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*******************************************************************************
* Copyright (c) 2020 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.lemminx.extensions.contentmodel;

import static org.eclipse.lemminx.XMLAssert.dl;
import static org.eclipse.lemminx.XMLAssert.r;

import org.eclipse.lemminx.XMLAssert;
import org.eclipse.lemminx.commons.BadLocationException;
import org.junit.jupiter.api.Test;

/**
* DTD document links tests
*
*/
public class DTDDocumentLinkTest {

@Test
public void docTypeSYSTEM() throws BadLocationException {
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"../dtd/base.dtd\" [\r\n" + //
"\r\n" + //
"]>\r\n" + //
"<root-element />";
XMLAssert.testDocumentLinkFor(xml, "src/test/resources/xml/base.xml",
dl(r(1, 31, 1, 46), "src/test/resources/dtd/base.dtd"));
}

@Test
public void docTypePUBLIC() throws BadLocationException {
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element PUBLIC \"ABCD\" \"../dtd/base.dtd\" [\r\n" + //
"\r\n" + //
"]>\r\n" + //
"<root-element />";
XMLAssert.testDocumentLinkFor(xml, "src/test/resources/xml/base.xml",
dl(r(1, 38, 1, 53), "src/test/resources/dtd/base.dtd"));
}

@Test
public void noLinks() throws BadLocationException {
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element \"ABCD\" \"../dtd/base.dtd\" [\r\n" + // here it misses PUBLIC
"\r\n" + //
"]>\r\n" + //
"<root-element />";
XMLAssert.testDocumentLinkFor(xml, "src/test/resources/xml/base.xml");
}
}
3 changes: 3 additions & 0 deletions org.eclipse.lemminx/src/test/resources/dtd/base.dtd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!ELEMENT root-element (#PCDATA)>
<!ENTITY foo "bar">
5 changes: 5 additions & 0 deletions org.eclipse.lemminx/src/test/resources/xml/base-public.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE root-element PUBLIC "ABCD" "../dtd/base.dtd" [

]>
<root-element />
5 changes: 5 additions & 0 deletions org.eclipse.lemminx/src/test/resources/xml/base.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE root-element SYSTEM "../dtd/base.dtd" [

]>
<root-element />

0 comments on commit 5883cae

Please sign in to comment.