浏览代码

Merge pull request #102 from VictorLoktev/master

Added check for restricted XML characters.
master
PrzemyslawKlys 8 年前
父节点
当前提交
17a7df543d
共有 6 个文件被更改,包括 203 次插入22 次删除
  1. 21
    2
      DocX/HelperFunctions.cs
  2. 6
    4
      DocX/Paragraph.cs
  3. 26
    15
      DocX/Table.cs
  4. 6
    0
      DocX/bin/Release/DocX.XML
  5. 二进制
      DocX/bin/Release/DocX.dll
  6. 144
    1
      UnitTests/DocXUnitTests.cs

+ 21
- 2
DocX/HelperFunctions.cs 查看文件

public const string DOCUMENT_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"; public const string DOCUMENT_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
public const string TEMPLATE_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml"; public const string TEMPLATE_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml";
public static bool IsNullOrWhiteSpace(this string value)
/// <summary>
/// List of restricted character in xml: [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]
/// See: https://www.w3.org/TR/xml11/#sec-xml11
/// </summary>
public static readonly char[] RestrictedXmlChar = new char[] {
'\x1','\x2','\x3','\x4','\x5','\x6','\x7','\x8','\xb','\xc','\xe','\xf',
'\x10','\x11','\x12','\x13','\x14','\x15','\x16','\x17','\x18','\x19','\x1a','\x1b','\x1c','\x1e','\x1f',
'\x7f','\x80','\x81','\x82','\x83','\x84','\x86','\x87','\x88','\x89','\x8a','\x8b','\x8c','\x8d','\x8e','\x8f',
'\x90','\x91','\x92','\x93','\x94','\x95','\x96','\x97','\x98','\x99','\x9a','\x9b','\x9c','\x9d','\x9e','\x9f'
};
public static bool IsNullOrWhiteSpace(this string value)
{ {
if (value == null) return true; if (value == null) return true;
return string.IsNullOrEmpty(value.Trim()); return string.IsNullOrEmpty(value.Trim());
break; break;
default: default:
sb.Append(c);
// Check the character against restricted list:
// RestrictedChar ::= [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]
// See https://www.w3.org/TR/xml11/#sec-xml11
if( RestrictedXmlChar.Contains( c ) )
{
// skip the character
}
else
sb.Append(c);
break; break;
} }

+ 6
- 4
DocX/Paragraph.cs 查看文件

XElement h_xml; XElement h_xml;
if (index == 0) if (index == 0)
{ {
// Add this hyperlink as the last element.
// Add this hyperlink as the first element.
Xml.AddFirst(h.Xml); Xml.AddFirst(h.Xml);
// Extract the picture back out of the DOM. // Extract the picture back out of the DOM.
h_xml = (XElement)run.Xml.NextNode; h_xml = (XElement)run.Xml.NextNode;
} }
h_xml.SetAttributeValue(DocX.r + "id", Id);
}
}
h_xml.SetAttributeValue( DocX.r + "id", Id );
return this;
this.runs = Xml.Elements().Last().Elements( XName.Get( "r", DocX.w.NamespaceName ) ).ToList();
return this;
} }
/// <summary> /// <summary>

+ 26
- 15
DocX/Table.cs 查看文件

if (design == TableDesign.Custom) if (design == TableDesign.Custom)
{ {
if (string.IsNullOrEmpty(_customTableDesignName))
{
design = TableDesign.None;
if (style != null)
style.Remove();
}
else
{
val.Value = _customTableDesignName;
}
}
else
#region Code is commented out
// The code gives a problem while copiing a table.
// Look at Test_Clone_Table_Twice method in test.
//Example:
//Table tab1 = doc.Tables[ 0 ];
//Table tab2 = doc.InsertTable( tab1 );
//Table tab3 = doc.InsertTable( tab2 ); - here we have exception at "var styleElement =" line below in this method
// The source of the problem is loosing the "<w:tblStyle w:val="a3"/>" by the commented code
//if (string.IsNullOrEmpty(_customTableDesignName))
//{
// design = TableDesign.None;
// if (style != null)
// style.Remove();
//}
//else
//{
// val.Value = _customTableDesignName;
//}
#endregion
}
else
{ {
switch (design) switch (design)
{ {
let styleId = e.Attribute(XName.Get("styleId", DocX.w.NamespaceName)) let styleId = e.Attribute(XName.Get("styleId", DocX.w.NamespaceName))
where (styleId != null && styleId.Value == val.Value) where (styleId != null && styleId.Value == val.Value)
select e select e
).First();
).FirstOrDefault();
Document.styles.Element(XName.Get("styles", DocX.w.NamespaceName)).Add(styleElement);
if( styleElement != null )
Document.styles.Element(XName.Get("styles", DocX.w.NamespaceName)).Add(styleElement);
} }
} }
} }

+ 6
- 0
DocX/bin/Release/DocX.XML 查看文件

The custom property to display. The custom property to display.
</summary> </summary>
</member> </member>
<member name="F:Novacode.HelperFunctions.RestrictedXmlChar">
<summary>
List of restricted character in xml: [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]
See: https://www.w3.org/TR/xml11/#sec-xml11
</summary>
</member>
<member name="M:Novacode.HelperFunctions.ContainsEveryChildOf(System.Xml.Linq.XElement,System.Xml.Linq.XElement,Novacode.MatchFormattingOptions)"> <member name="M:Novacode.HelperFunctions.ContainsEveryChildOf(System.Xml.Linq.XElement,System.Xml.Linq.XElement,Novacode.MatchFormattingOptions)">
<summary> <summary>
Checks whether 'toCheck' has all children that 'desired' has and values of 'val' attributes are the same Checks whether 'toCheck' has all children that 'desired' has and values of 'val' attributes are the same

二进制
DocX/bin/Release/DocX.dll 查看文件


+ 144
- 1
UnitTests/DocXUnitTests.cs 查看文件

} }
} }
[Test]
public void Test_InvalidCharacter()
{
using( var output = File.Open( Path.Combine( _directoryWithFiles, "InvalidCharacters.docx" ), FileMode.Create ) )
{
using( var doc = DocX.Create( output ) )
{
doc.InsertParagraph( "\b" );
Exception ex = null;
try
{
doc.Save();
}
catch( Exception e )
{
ex = e;
}
Assert.IsTrue( ex == null );
}
}
}
/// <summary> /// <summary>
/// TextRemove should not remove empty paragraphs in case the paragraph is alone in the cell. /// TextRemove should not remove empty paragraphs in case the paragraph is alone in the cell.
/// In the rest cases empty paragraph may be removed. /// In the rest cases empty paragraph may be removed.
} }
} }
[Test]
public void Test_Clone_Table_Twice()
{
using( var input = File.Open( Path.Combine( _directoryWithFiles, "TableSpecifiedHeights.docx" ), FileMode.Open ) )
{
using( var doc = DocX.Load( input ) )
{
// Make sure content of the file is ok for test
Assert.IsTrue( doc.Tables.Count == 1 );
Table tab1 = doc.Tables[ 0 ];
doc.InsertParagraph( "" );
Table tab2 = doc.InsertTable( tab1 );
Assert.IsTrue( doc.Tables.Count == 2 );
doc.InsertParagraph( "" );
Table tab3 = doc.InsertTable( tab2 );
Assert.IsTrue( doc.Tables.Count == 3 );
doc.SaveAs( Path.Combine( _directoryWithFiles, "TwoClonedTables.docx" ) );
}
}
}
public string ReplaceFunc(string findStr) public string ReplaceFunc(string findStr)
{ {
var testPatterns = new Dictionary<string, string> var testPatterns = new Dictionary<string, string>
} }
} }
[Test]
/// <summary>
/// This test fills two tables with hyperlinks.
/// </summary>
[Test]
public void Test_Insert_Hyperlink_In_Tables()
{
using( var input = File.Open( Path.Combine( _directoryWithFiles, "TableSpecifiedHeights.docx" ), FileMode.Open ) )
{
using( var doc = DocX.Load( input ) )
{
// Make sure content of the file is ok for test
Assert.IsTrue( doc.Tables.Count > 0 );
Table tab1 = doc.Tables[ 0 ];
Assert.IsTrue( tab1.RowCount > 0 );
Assert.IsTrue( tab1.Rows[0].ColumnCount > 0 );
doc.InsertParagraph( "" );
Table tab2 = doc.InsertTable( tab1 );
Assert.IsTrue( tab2.RowCount > 0 );
Row row1 = tab1.Rows[ 0 ];
Row row2 = tab2.Rows[ 0 ];
// 10 times insert hyperlinks in both tables in tic-tak order
for( int index = 0; index < 10; index++ )
{
Row newRow1 = tab1.InsertRow( row1 );
Row newRow2 = tab2.InsertRow( row2 );
Hyperlink h1 = doc.AddHyperlink(
string.Format( "Table {0}, Row {1}. Google searches for {0} {1}", 1, index + 1 ),
new Uri( string.Format( "https://www.google.com/search?q=Table{0}Row{1}", 1, index + 1 ) ) );
newRow1.Cells[ 0 ].Paragraphs[ 0 ].InsertHyperlink( h1 );
Hyperlink h2 = doc.AddHyperlink(
string.Format( "Table {0}, Row {1}. Google searches for {0} {1}", 2, index + 1 ),
new Uri( string.Format( "https://www.google.com/search?q=Table{0}Row{1}", 2, index + 1 ) ) );
newRow2.Cells[ 0 ].Paragraphs[ 0 ].InsertHyperlink( h2 );
}
//Make sure links are ok and in right order
for( int index = 0; index < doc.Hyperlinks.Count; index++ )
{
Hyperlink h = doc.Hyperlinks[ index ];
string text = string.Format( "Table {0}, Row {1}. Google searches for {0} {1}", ( index / 10 ) + 1, ( index ) % 10 + 1 );
string uri = string.Format( "https://www.google.com/search?q=Table{0}Row{1}", ( index / 10 ) + 1, ( index ) % 10 + 1 );
Assert.IsTrue( string.Compare( h.Text, text ) == 0 );
Assert.IsTrue( h.Uri != null );
Assert.IsTrue( string.Compare( h.Uri.ToString(), uri ) == 0 );
}
doc.SaveAs( Path.Combine( _directoryDocuments, "Test_Insert_Hyperlink_In_Tables.docx" ) );
}
}
}
/// <summary>
/// This test makes 2 file. The first uses InsertHyperlink. The second uses AppendHyperlink.
/// The both hyperlink collections should be equal to each other.
/// We need be sure the bug in InsertHyperlink is fixed (id attribute in hyperlink was empty and order of inserteed hyperlinks was broken).
/// </summary>
[Test]
public void Test_Compare_InsertHyperlink_And_AppendHyperLinks()
{
string fileName1 = Path.Combine( _directoryDocuments, "Test_InsertHyperLinks.docx" );
string fileName2 = Path.Combine( _directoryDocuments, "Test_AppendHyperlinks.docx" );
using( DocX document1 = DocX.Create( fileName1 ) )
{
using( DocX document2 = DocX.Create( fileName2 ) )
{
for( int index = 0; index < 10; index++ )
{
Hyperlink h = document1.AddHyperlink(
string.Format( "Google searches for {0}", index + 1 ),
new Uri( string.Format( "https://www.google.com/search?q={0}", index + 1 ) ) );
document1.InsertParagraph( "" ).InsertHyperlink( h );
}
document1.Save();
for( int index = 0; index < 10; index++ )
{
Hyperlink h = document2.AddHyperlink(
string.Format( "Google searches for {0}", index + 1 ),
new Uri( string.Format( "https://www.google.com/search?q={0}", index + 1 ) ) );
document2.InsertParagraph( "" ).AppendHyperlink( h );
}
document2.Save();
Assert.IsTrue( document1.Hyperlinks.Count == document2.Hyperlinks.Count );
for( int index = 0; index < document1.Hyperlinks.Count; index++ )
{
Hyperlink h1 = document1.Hyperlinks[ index ];
Hyperlink h2 = document2.Hyperlinks[ index ];
Assert.IsTrue( string.Compare( h1.Text, h2.Text ) == 0 );
Assert.IsTrue( string.Compare( h1.Uri.ToString(), h2.Uri.ToString() ) == 0 );
}
}
}
}
[Test]
public void Test_Insert_Hyperlink() public void Test_Insert_Hyperlink()
{ {
// Load test document. // Load test document.

正在加载...
取消
保存